/src/libreoffice/svtools/source/brwbox/brwbox1.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <comphelper/diagnose_ex.hxx> |
21 | | #include <svtools/brwbox.hxx> |
22 | | #include <svtools/brwhead.hxx> |
23 | | #include <svtools/scrolladaptor.hxx> |
24 | | #include <o3tl/numeric.hxx> |
25 | | #include <o3tl/safeint.hxx> |
26 | | #include "datwin.hxx" |
27 | | #include <osl/diagnose.h> |
28 | | #include <tools/debug.hxx> |
29 | | #include <tools/fract.hxx> |
30 | | #include <sal/log.hxx> |
31 | | #include <vcl/InterimItemWindow.hxx> |
32 | | #include <vcl/svapp.hxx> |
33 | | #include <vcl/weld/Entry.hxx> |
34 | | #include <vcl/weld/weld.hxx> |
35 | | #include <vcl/weld/Builder.hxx> |
36 | | |
37 | | #include <algorithm> |
38 | | #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> |
39 | | #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp> |
40 | | #include <com/sun/star/accessibility/AccessibleEventId.hpp> |
41 | | #include <com/sun/star/lang/XComponent.hpp> |
42 | | #include <tools/multisel.hxx> |
43 | | |
44 | | |
45 | 0 | #define SCROLL_FLAGS (ScrollFlags::Clip | ScrollFlags::NoChildren) |
46 | | |
47 | | using namespace com::sun::star::accessibility::AccessibleTableModelChangeType; |
48 | | using com::sun::star::accessibility::AccessibleTableModelChange; |
49 | | using namespace com::sun::star::accessibility; |
50 | | using namespace ::com::sun::star::uno; |
51 | | using namespace svt; |
52 | | |
53 | | namespace |
54 | | { |
55 | | |
56 | | void disposeAndClearHeaderCell(BrowseBox::THeaderCellMap& _rHeaderCell) |
57 | 0 | { |
58 | 0 | ::std::for_each( |
59 | 0 | _rHeaderCell.begin(), _rHeaderCell.end(), |
60 | 0 | [](const BrowseBox::THeaderCellMap::value_type& rType) |
61 | 0 | { |
62 | 0 | css::uno::Reference<css::lang::XComponent> xComp(rType.second, css::uno::UNO_QUERY); |
63 | 0 | OSL_ENSURE(xComp.is() || !rType.second.is(), |
64 | 0 | "THeaderCellMapFunctorDispose: invalid accessible cell (no XComponent)!"); |
65 | 0 | if (xComp.is()) |
66 | 0 | try |
67 | 0 | { |
68 | 0 | xComp->dispose(); |
69 | 0 | } |
70 | 0 | catch (const css::uno::Exception&) |
71 | 0 | { |
72 | 0 | TOOLS_WARN_EXCEPTION("svtools", "THeaderCellMapFunctorDispose"); |
73 | 0 | } |
74 | 0 | }); |
75 | 0 | _rHeaderCell.clear(); |
76 | 0 | } |
77 | | } |
78 | | |
79 | | // we're just measuring the "real" NavigationBar |
80 | | class MeasureStatusBar final : public InterimItemWindow |
81 | | { |
82 | | private: |
83 | | std::unique_ptr<weld::Label> m_xRecordText; |
84 | | std::unique_ptr<weld::Entry> m_xAbsolute; |
85 | | std::unique_ptr<weld::Label> m_xRecordOf; |
86 | | std::unique_ptr<weld::Label> m_xRecordCount; |
87 | | public: |
88 | | MeasureStatusBar(vcl::Window *pParent) |
89 | 0 | : InterimItemWindow(pParent, u"svx/ui/navigationbar.ui"_ustr, u"NavigationBar"_ustr) |
90 | 0 | , m_xRecordText(m_xBuilder->weld_label(u"recordtext"_ustr)) |
91 | 0 | , m_xAbsolute(m_xBuilder->weld_entry(u"entry-noframe"_ustr)) |
92 | 0 | , m_xRecordOf(m_xBuilder->weld_label(u"recordof"_ustr)) |
93 | 0 | , m_xRecordCount(m_xBuilder->weld_label(u"recordcount"_ustr)) |
94 | 0 | { |
95 | 0 | vcl::Font aApplFont(Application::GetSettings().GetStyleSettings().GetToolFont()); |
96 | 0 | m_xAbsolute->set_font(aApplFont); |
97 | 0 | m_xRecordText->set_font(aApplFont); |
98 | 0 | m_xRecordOf->set_font(aApplFont); |
99 | 0 | m_xRecordCount->set_font(aApplFont); |
100 | |
|
101 | 0 | SetSizePixel(get_preferred_size()); |
102 | 0 | } |
103 | | |
104 | | virtual void dispose() override |
105 | 0 | { |
106 | 0 | m_xRecordCount.reset(); |
107 | 0 | m_xRecordOf.reset(); |
108 | 0 | m_xAbsolute.reset(); |
109 | 0 | m_xRecordText.reset(); |
110 | 0 | InterimItemWindow::dispose(); |
111 | 0 | } |
112 | | }; |
113 | | |
114 | | tools::Long BrowseBox::GetBarHeight() const |
115 | 0 | { |
116 | 0 | tools::Long nScrollBarSize = GetSettings().GetStyleSettings().GetScrollBarSize(); |
117 | 0 | if (!m_bNavigationBar) |
118 | 0 | return nScrollBarSize; |
119 | | |
120 | | // tdf#115941 because some platforms have things like overlay scrollbars, take a max |
121 | | // of a statusbar height and a scrollbar height as the control area height |
122 | | |
123 | | // (we can't ask the scrollbars for their size cause if we're zoomed they still have to be |
124 | | // resized - which is done in UpdateScrollbars) |
125 | 0 | return std::max(aStatusBarHeight->GetSizePixel().Height(), nScrollBarSize); |
126 | 0 | } |
127 | | |
128 | | BrowseBox::BrowseBox( vcl::Window* pParent, WinBits nBits, BrowserMode nMode ) |
129 | 0 | :Control( pParent, nBits | WB_3DLOOK ) |
130 | 0 | ,DragSourceHelper( this ) |
131 | 0 | ,DropTargetHelper( this ) |
132 | 0 | ,aHScroll( VclPtr<ScrollAdaptor>::Create(this, true) ) |
133 | | // see NavigationBar ctor, here we just want to know its height |
134 | 0 | ,aStatusBarHeight(VclPtr<MeasureStatusBar>::Create(this)) |
135 | 0 | ,m_nCornerHeight(0) |
136 | 0 | ,m_nCornerWidth(0) |
137 | 0 | ,m_nActualCornerWidth(0) |
138 | 0 | ,m_bNavigationBar(false) |
139 | 0 | { |
140 | 0 | bMultiSelection = false; |
141 | 0 | pColSel = nullptr; |
142 | 0 | pVScroll = nullptr; |
143 | 0 | pDataWin = VclPtr<BrowserDataWin>::Create( this ).get(); |
144 | |
|
145 | 0 | InitSettings_Impl( this ); |
146 | 0 | InitSettings_Impl( pDataWin ); |
147 | |
|
148 | 0 | bBootstrapped = false; |
149 | 0 | m_nDataRowHeight = 0; |
150 | 0 | nTitleLines = 1; |
151 | 0 | nFirstCol = 0; |
152 | 0 | nTopRow = 0; |
153 | 0 | nCurRow = BROWSER_ENDOFSELECTION; |
154 | 0 | nCurColId = 0; |
155 | 0 | nResizeX = 0; |
156 | 0 | nMinResizeX = 0; |
157 | 0 | nDragX = 0; |
158 | 0 | nResizeCol = 0; |
159 | 0 | bResizing = false; |
160 | 0 | bSelect = false; |
161 | 0 | bSelecting = false; |
162 | 0 | bScrolling = false; |
163 | 0 | bSelectionIsVisible = false; |
164 | 0 | bNotToggleSel = false; |
165 | 0 | bRowDividerDrag = false; |
166 | 0 | bHit = false; |
167 | 0 | mbInteractiveRowHeight = false; |
168 | 0 | bHideSelect = false; |
169 | 0 | bHideCursor = TRISTATE_FALSE; |
170 | 0 | nRowCount = 0; |
171 | 0 | m_bFocusOnlyCursor = true; |
172 | 0 | m_aCursorColor = COL_TRANSPARENT; |
173 | 0 | m_nCurrentMode = BrowserMode::NONE; |
174 | 0 | nControlAreaWidth = USHRT_MAX; |
175 | 0 | uRow.nSel = BROWSER_ENDOFSELECTION; |
176 | |
|
177 | 0 | aHScroll->SetLineSize(1); |
178 | 0 | aHScroll->SetScrollHdl( LINK( this, BrowseBox, HorzScrollHdl ) ); |
179 | 0 | pDataWin->Show(); |
180 | |
|
181 | 0 | SetMode( nMode ); |
182 | 0 | bSelectionIsVisible = bKeepHighlight; |
183 | 0 | bHasFocus = HasChildPathFocus(); |
184 | 0 | pDataWin->nCursorHidden = |
185 | 0 | ( bHasFocus ? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 ); |
186 | 0 | } |
187 | | |
188 | | BrowseBox::~BrowseBox() |
189 | 0 | { |
190 | 0 | disposeOnce(); |
191 | 0 | } |
192 | | |
193 | | void BrowseBox::DisposeAccessible() |
194 | 0 | { |
195 | 0 | if (m_xAccessible) |
196 | 0 | { |
197 | 0 | disposeAndClearHeaderCell(m_aColHeaderCellMap); |
198 | 0 | disposeAndClearHeaderCell(m_aRowHeaderCellMap); |
199 | 0 | m_xAccessible->dispose(); |
200 | 0 | m_xAccessible = nullptr; |
201 | 0 | } |
202 | 0 | } |
203 | | |
204 | | void BrowseBox::dispose() |
205 | 0 | { |
206 | 0 | SAL_INFO("svtools", "BrowseBox:dispose " << this ); |
207 | | |
208 | 0 | DisposeAccessible(); |
209 | |
|
210 | 0 | Hide(); |
211 | 0 | pDataWin->pHeaderBar.disposeAndClear(); |
212 | 0 | pDataWin.disposeAndClear(); |
213 | 0 | pVScroll.disposeAndClear(); |
214 | 0 | aHScroll.disposeAndClear(); |
215 | 0 | aStatusBarHeight.disposeAndClear(); |
216 | | |
217 | | // free columns-space |
218 | 0 | mvCols.clear(); |
219 | 0 | pColSel.reset(); |
220 | 0 | if ( bMultiSelection ) |
221 | 0 | delete uRow.pSel; |
222 | 0 | DragSourceHelper::dispose(); |
223 | 0 | DropTargetHelper::dispose(); |
224 | 0 | Control::dispose(); |
225 | 0 | } |
226 | | |
227 | | |
228 | | short BrowseBox::GetCursorHideCount() const |
229 | 0 | { |
230 | 0 | return pDataWin->nCursorHidden; |
231 | 0 | } |
232 | | |
233 | | |
234 | | void BrowseBox::DoShowCursor() |
235 | 0 | { |
236 | 0 | if (!pDataWin) |
237 | 0 | return; |
238 | 0 | short nHiddenCount = --pDataWin->nCursorHidden; |
239 | 0 | if (PaintCursorIfHiddenOnce()) |
240 | 0 | { |
241 | 0 | if (1 == nHiddenCount) |
242 | 0 | DrawCursor(); |
243 | 0 | } |
244 | 0 | else |
245 | 0 | { |
246 | 0 | if (0 == nHiddenCount) |
247 | 0 | DrawCursor(); |
248 | 0 | } |
249 | 0 | } |
250 | | |
251 | | |
252 | | void BrowseBox::DoHideCursor() |
253 | 0 | { |
254 | 0 | short nHiddenCount = ++pDataWin->nCursorHidden; |
255 | 0 | if (PaintCursorIfHiddenOnce()) |
256 | 0 | { |
257 | 0 | if (2 == nHiddenCount) |
258 | 0 | DrawCursor(); |
259 | 0 | } |
260 | 0 | else |
261 | 0 | { |
262 | 0 | if (1 == nHiddenCount) |
263 | 0 | DrawCursor(); |
264 | 0 | } |
265 | 0 | } |
266 | | |
267 | | |
268 | | void BrowseBox::SetRealRowCount( const OUString &rRealRowCount ) |
269 | 0 | { |
270 | 0 | pDataWin->aRealRowCount = rRealRowCount; |
271 | 0 | } |
272 | | |
273 | | |
274 | | void BrowseBox::SetFont( const vcl::Font& rNewFont ) |
275 | 0 | { |
276 | 0 | pDataWin->SetFont( rNewFont ); |
277 | 0 | ImpGetDataRowHeight(); |
278 | 0 | } |
279 | | |
280 | | const vcl::Font& BrowseBox::GetFont() const |
281 | 0 | { |
282 | 0 | return pDataWin->GetFont(); |
283 | 0 | } |
284 | | |
285 | | tools::Long BrowseBox::GetDefaultColumnWidth( const OUString& _rText ) const |
286 | 0 | { |
287 | 0 | return pDataWin->GetTextWidth( _rText ) + pDataWin->GetTextWidth(OUString('0')) * 4; |
288 | 0 | } |
289 | | |
290 | | |
291 | | void BrowseBox::InsertHandleColumn( tools::Long nWidth ) |
292 | 0 | { |
293 | |
|
294 | | #if OSL_DEBUG_LEVEL > 0 |
295 | | OSL_ENSURE( ColCount() == 0 || mvCols[0]->GetId() != HandleColumnId , "BrowseBox::InsertHandleColumn: there is already a handle column" ); |
296 | | { |
297 | | for (auto const & col : mvCols) |
298 | | OSL_ENSURE( col->GetId() != HandleColumnId, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" ); |
299 | | } |
300 | | #endif |
301 | |
|
302 | 0 | mvCols.insert( mvCols.begin(), std::unique_ptr<BrowserColumn>(new BrowserColumn( 0, OUString(), nWidth, GetZoom() )) ); |
303 | 0 | FreezeColumn( 0 ); |
304 | | |
305 | | // adjust headerbar |
306 | 0 | if ( pDataWin->pHeaderBar ) |
307 | 0 | { |
308 | 0 | pDataWin->pHeaderBar->SetPosSizePixel( |
309 | 0 | Point(nWidth, 0), |
310 | 0 | Size( GetOutputSizePixel().Width() - nWidth, GetTitleHeight() ) |
311 | 0 | ); |
312 | 0 | } |
313 | |
|
314 | 0 | ColumnInserted( 0 ); |
315 | 0 | } |
316 | | |
317 | | |
318 | | void BrowseBox::InsertDataColumn( sal_uInt16 nItemId, const OUString& rText, |
319 | | tools::Long nWidth, HeaderBarItemBits nBits, sal_uInt16 nPos ) |
320 | 0 | { |
321 | |
|
322 | 0 | OSL_ENSURE( nItemId != HandleColumnId, "BrowseBox::InsertDataColumn: nItemId is HandleColumnId" ); |
323 | 0 | OSL_ENSURE( nItemId != BROWSER_INVALIDID, "BrowseBox::InsertDataColumn: nItemId is reserved value BROWSER_INVALIDID" ); |
324 | |
|
325 | | #if OSL_DEBUG_LEVEL > 0 |
326 | | { |
327 | | for (auto const& col : mvCols) |
328 | | OSL_ENSURE( col->GetId() != nItemId, "BrowseBox::InsertDataColumn: duplicate column Id" ); |
329 | | } |
330 | | #endif |
331 | |
|
332 | 0 | if ( nPos < mvCols.size() ) |
333 | 0 | { |
334 | 0 | mvCols.emplace( mvCols.begin() + nPos, new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) ); |
335 | 0 | } |
336 | 0 | else |
337 | 0 | { |
338 | 0 | mvCols.emplace_back( new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) ); |
339 | 0 | } |
340 | 0 | if ( nCurColId == 0 ) |
341 | 0 | nCurColId = nItemId; |
342 | |
|
343 | 0 | if ( pDataWin->pHeaderBar ) |
344 | 0 | { |
345 | | // Handle column not in the header bar |
346 | 0 | sal_uInt16 nHeaderPos = nPos; |
347 | 0 | if (nHeaderPos != HEADERBAR_APPEND && GetColumnId(0) == HandleColumnId ) |
348 | 0 | nHeaderPos--; |
349 | 0 | pDataWin->pHeaderBar->InsertItem( |
350 | 0 | nItemId, rText, nWidth, nBits, nHeaderPos ); |
351 | 0 | } |
352 | 0 | ColumnInserted( nPos ); |
353 | 0 | } |
354 | | |
355 | | sal_uInt16 BrowseBox::ToggleSelectedColumn() |
356 | 0 | { |
357 | 0 | sal_uInt16 nSelectedColId = BROWSER_INVALIDID; |
358 | 0 | if ( pColSel && pColSel->GetSelectCount() ) |
359 | 0 | { |
360 | 0 | DoHideCursor(); |
361 | 0 | ToggleSelection(); |
362 | 0 | tools::Long nSelected = pColSel->FirstSelected(); |
363 | 0 | if (nSelected != static_cast<tools::Long>(SFX_ENDOFSELECTION)) |
364 | 0 | nSelectedColId = mvCols[nSelected]->GetId(); |
365 | 0 | pColSel->SelectAll(false); |
366 | 0 | } |
367 | 0 | return nSelectedColId; |
368 | 0 | } |
369 | | |
370 | | void BrowseBox::SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId) |
371 | 0 | { |
372 | 0 | if ( pColSel && _nSelectedColumnId != BROWSER_INVALIDID ) |
373 | 0 | { |
374 | 0 | pColSel->Select( GetColumnPos( _nSelectedColumnId ) ); |
375 | 0 | ToggleSelection(); |
376 | 0 | SAL_INFO("svtools", "BrowseBox::SetToggledSelectedColumn " << this ); |
377 | 0 | DoShowCursor(); |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | | void BrowseBox::FreezeColumn( sal_uInt16 nItemId ) |
382 | 0 | { |
383 | | // get the position in the current array |
384 | 0 | size_t nItemPos = GetColumnPos( nItemId ); |
385 | 0 | if ( nItemPos >= mvCols.size() ) |
386 | | // not available! |
387 | 0 | return; |
388 | | |
389 | | // doesn't the state change? |
390 | 0 | if ( mvCols[ nItemPos ]->IsFrozen() ) |
391 | 0 | return; |
392 | | |
393 | | // remark the column selection |
394 | 0 | sal_uInt16 nSelectedColId = ToggleSelectedColumn(); |
395 | | |
396 | | // to be moved? |
397 | 0 | if ( nItemPos != 0 && !mvCols[ nItemPos-1 ]->IsFrozen() ) |
398 | 0 | { |
399 | | // move to the right of the last frozen column |
400 | 0 | sal_uInt16 nFirstScrollable = FrozenColCount(); |
401 | 0 | std::unique_ptr<BrowserColumn> pColumn = std::move(mvCols[ nItemPos ]); |
402 | 0 | mvCols.erase( mvCols.begin() + nItemPos ); |
403 | 0 | nItemPos = nFirstScrollable; |
404 | 0 | mvCols.insert( mvCols.begin() + nItemPos, std::move(pColumn) ); |
405 | 0 | } |
406 | | |
407 | | // adjust the number of the first scrollable and visible column |
408 | 0 | if ( nFirstCol <= nItemPos ) |
409 | 0 | nFirstCol = nItemPos + 1; |
410 | | |
411 | | // toggle the freeze-state of the column |
412 | 0 | mvCols[ nItemPos ]->Freeze(); |
413 | | |
414 | | // align the scrollbar-range |
415 | 0 | UpdateScrollbars(); |
416 | | |
417 | | // repaint |
418 | 0 | Control::Invalidate(); |
419 | 0 | pDataWin->Invalidate(); |
420 | | |
421 | | // remember the column selection |
422 | 0 | SetToggledSelectedColumn(nSelectedColId); |
423 | 0 | } |
424 | | |
425 | | |
426 | | void BrowseBox::SetColumnPos( sal_uInt16 nColumnId, sal_uInt16 nPos ) |
427 | 0 | { |
428 | | // never set pos of the handle column |
429 | 0 | if ( nColumnId == HandleColumnId ) |
430 | 0 | return; |
431 | | |
432 | | // get the position in the current array |
433 | 0 | sal_uInt16 nOldPos = GetColumnPos( nColumnId ); |
434 | 0 | if ( nOldPos >= mvCols.size() ) |
435 | | // not available! |
436 | 0 | return; |
437 | | |
438 | | // does the state change? |
439 | 0 | if (nOldPos == nPos) |
440 | 0 | return; |
441 | | |
442 | | // remark the column selection |
443 | 0 | sal_uInt16 nSelectedColId = ToggleSelectedColumn(); |
444 | | |
445 | | // determine old column area |
446 | 0 | Size aDataWinSize( pDataWin->GetSizePixel() ); |
447 | 0 | if ( pDataWin->pHeaderBar ) |
448 | 0 | aDataWinSize.AdjustHeight(pDataWin->pHeaderBar->GetSizePixel().Height() ); |
449 | |
|
450 | 0 | tools::Rectangle aFromRect( GetFieldRect( nColumnId) ); |
451 | 0 | aFromRect.AdjustRight(2*MIN_COLUMNWIDTH ); |
452 | |
|
453 | 0 | sal_uInt16 nNextPos = nOldPos + 1; |
454 | 0 | if ( nOldPos > nPos ) |
455 | 0 | nNextPos = nOldPos - 1; |
456 | |
|
457 | 0 | BrowserColumn *pNextCol = mvCols[ nNextPos ].get(); |
458 | 0 | tools::Rectangle aNextRect(GetFieldRect( pNextCol->GetId() )); |
459 | | |
460 | | // move column internally |
461 | 0 | { |
462 | 0 | std::unique_ptr<BrowserColumn> pTemp = std::move(mvCols[nOldPos]); |
463 | 0 | mvCols.erase( mvCols.begin() + nOldPos ); |
464 | 0 | mvCols.insert( mvCols.begin() + nPos, std::move(pTemp) ); |
465 | 0 | } |
466 | | |
467 | | // determine new column area |
468 | 0 | tools::Rectangle aToRect( GetFieldRect( nColumnId ) ); |
469 | 0 | aToRect.AdjustRight(2*MIN_COLUMNWIDTH ); |
470 | | |
471 | | // do scroll, let redraw |
472 | 0 | if( pDataWin->GetBackground().IsScrollable() ) |
473 | 0 | { |
474 | 0 | tools::Long nScroll = -aFromRect.GetWidth(); |
475 | 0 | tools::Rectangle aScrollArea; |
476 | 0 | if ( nOldPos > nPos ) |
477 | 0 | { |
478 | 0 | tools::Long nFrozenWidth = GetFrozenWidth(); |
479 | 0 | if ( aToRect.Left() < nFrozenWidth ) |
480 | 0 | aToRect.SetLeft( nFrozenWidth ); |
481 | 0 | aScrollArea = tools::Rectangle(Point(aToRect.Left(),0), |
482 | 0 | Point(aNextRect.Right(),aDataWinSize.Height())); |
483 | 0 | nScroll *= -1; // reverse direction |
484 | 0 | } |
485 | 0 | else |
486 | 0 | aScrollArea = tools::Rectangle(Point(aNextRect.Left(),0), |
487 | 0 | Point(aToRect.Right(),aDataWinSize.Height())); |
488 | |
|
489 | 0 | pDataWin->Scroll( nScroll, 0, aScrollArea ); |
490 | 0 | aToRect.SetTop( 0 ); |
491 | 0 | aToRect.SetBottom( aScrollArea.Bottom() ); |
492 | 0 | Invalidate( aToRect ); |
493 | 0 | } |
494 | 0 | else |
495 | 0 | pDataWin->Window::Invalidate( InvalidateFlags::NoChildren ); |
496 | | |
497 | | // adjust header bar positions |
498 | 0 | if ( pDataWin->pHeaderBar ) |
499 | 0 | { |
500 | 0 | sal_uInt16 nNewPos = nPos; |
501 | 0 | if ( GetColumnId(0) == HandleColumnId ) |
502 | 0 | --nNewPos; |
503 | 0 | pDataWin->pHeaderBar->MoveItem(nColumnId,nNewPos); |
504 | 0 | } |
505 | | // remember the column selection |
506 | 0 | SetToggledSelectedColumn(nSelectedColId); |
507 | |
|
508 | 0 | if ( !isAccessibleAlive() ) |
509 | 0 | return; |
510 | | |
511 | 0 | commitTableEvent( |
512 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
513 | 0 | Any( AccessibleTableModelChange( |
514 | 0 | COLUMNS_REMOVED, |
515 | 0 | -1, |
516 | 0 | -1, |
517 | 0 | nOldPos, |
518 | 0 | nOldPos |
519 | 0 | ) |
520 | 0 | ), |
521 | 0 | Any() |
522 | 0 | ); |
523 | |
|
524 | 0 | commitTableEvent( |
525 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
526 | 0 | Any( AccessibleTableModelChange( |
527 | 0 | COLUMNS_INSERTED, |
528 | 0 | -1, |
529 | 0 | -1, |
530 | 0 | nPos, |
531 | 0 | nPos |
532 | 0 | ) |
533 | 0 | ), |
534 | 0 | Any() |
535 | 0 | ); |
536 | |
|
537 | 0 | } |
538 | | |
539 | | |
540 | | void BrowseBox::SetColumnTitle( sal_uInt16 nItemId, const OUString& rTitle ) |
541 | 0 | { |
542 | | |
543 | | // never set title of the handle-column |
544 | 0 | if ( nItemId == HandleColumnId ) |
545 | 0 | return; |
546 | | |
547 | | // get the position in the current array |
548 | 0 | sal_uInt16 nItemPos = GetColumnPos( nItemId ); |
549 | 0 | if ( nItemPos >= mvCols.size() ) |
550 | | // not available! |
551 | 0 | return; |
552 | | |
553 | | // does the state change? |
554 | 0 | BrowserColumn *pCol = mvCols[ nItemPos ].get(); |
555 | 0 | if ( pCol->Title() == rTitle ) |
556 | 0 | return; |
557 | | |
558 | 0 | OUString sOld(pCol->Title()); |
559 | |
|
560 | 0 | pCol->Title() = rTitle; |
561 | | |
562 | | // adjust headerbar column |
563 | 0 | if ( pDataWin->pHeaderBar ) |
564 | 0 | pDataWin->pHeaderBar->SetItemText( nItemId, rTitle ); |
565 | 0 | else |
566 | 0 | { |
567 | | // redraw visible columns |
568 | 0 | if ( GetUpdateMode() && ( pCol->IsFrozen() || nItemPos > nFirstCol ) ) |
569 | 0 | Invalidate( tools::Rectangle( Point(0,0), |
570 | 0 | Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) ); |
571 | 0 | } |
572 | |
|
573 | 0 | if ( isAccessibleAlive() ) |
574 | 0 | { |
575 | 0 | commitTableEvent(AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED, |
576 | 0 | Any( rTitle ), |
577 | 0 | Any( sOld ) |
578 | 0 | ); |
579 | 0 | } |
580 | 0 | } |
581 | | |
582 | | |
583 | | void BrowseBox::SetColumnWidth( sal_uInt16 nItemId, tools::Long nWidth ) |
584 | 0 | { |
585 | | |
586 | | // get the position in the current array |
587 | 0 | size_t nItemPos = GetColumnPos( nItemId ); |
588 | 0 | if ( nItemPos >= mvCols.size() ) |
589 | 0 | return; |
590 | | |
591 | | // does the state change? |
592 | 0 | if ( nWidth < LONG_MAX && mvCols[ nItemPos ]->Width() == nWidth ) |
593 | 0 | return; |
594 | | |
595 | 0 | tools::Long nOldWidth = mvCols[ nItemPos ]->Width(); |
596 | | |
597 | | // adjust last column, if necessary |
598 | 0 | if ( nItemPos == mvCols.size() - 1 ) |
599 | 0 | { |
600 | 0 | if ( IsVisible() ) |
601 | 0 | { |
602 | 0 | tools::Long nMaxWidth = pDataWin->GetSizePixel().Width(); |
603 | 0 | nMaxWidth -= pDataWin->bAutoSizeLastCol |
604 | 0 | ? GetFieldRect(nItemId).Left() |
605 | 0 | : GetFrozenWidth(); |
606 | 0 | if ( pDataWin->bAutoSizeLastCol || nWidth > nMaxWidth ) |
607 | 0 | { |
608 | 0 | nWidth = nMaxWidth > 16 ? nMaxWidth : nOldWidth; |
609 | 0 | } |
610 | 0 | } |
611 | 0 | else if ( nWidth == LONG_MAX ) |
612 | 0 | { |
613 | | // If we can’t calculate the maximum width because the window isn’t visible then it’s |
614 | | // better to leave the width as it is than to set it to LONG_MAX. The last column width |
615 | | // will be recalculated when the window is shown anyway because the window will be |
616 | | // resized. |
617 | 0 | return; |
618 | 0 | } |
619 | 0 | } |
620 | | |
621 | | // OV |
622 | | // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff. |
623 | | // Thus, check here, if the width has actually changed. |
624 | 0 | if( nOldWidth == nWidth ) |
625 | 0 | return; |
626 | | |
627 | | // do we want to display the change immediately? |
628 | 0 | bool bUpdate = GetUpdateMode() && |
629 | 0 | ( mvCols[ nItemPos ]->IsFrozen() || nItemPos >= nFirstCol ); |
630 | |
|
631 | 0 | if ( bUpdate ) |
632 | 0 | { |
633 | | // Selection hidden |
634 | 0 | DoHideCursor(); |
635 | 0 | ToggleSelection(); |
636 | | //!pDataWin->Update(); |
637 | | //!Control::Update(); |
638 | 0 | } |
639 | | |
640 | | // set width |
641 | 0 | mvCols[ nItemPos ]->SetWidth(nWidth, GetZoom()); |
642 | | |
643 | | // scroll and invalidate |
644 | 0 | if ( bUpdate ) |
645 | 0 | { |
646 | | // get X-Pos of the column changed |
647 | 0 | tools::Long nX = 0; |
648 | 0 | for ( size_t nCol = 0; nCol < nItemPos; ++nCol ) |
649 | 0 | { |
650 | 0 | BrowserColumn *pCol = mvCols[ nCol ].get(); |
651 | 0 | if ( pCol->IsFrozen() || nCol >= nFirstCol ) |
652 | 0 | nX += pCol->Width(); |
653 | 0 | } |
654 | | |
655 | | // actually scroll+invalidate |
656 | 0 | pDataWin->GetOutDev()->SetClipRegion(); |
657 | 0 | bool bSelVis = bSelectionIsVisible; |
658 | 0 | bSelectionIsVisible = false; |
659 | 0 | if( GetBackground().IsScrollable() ) |
660 | 0 | { |
661 | |
|
662 | 0 | tools::Rectangle aScrRect( nX + std::min( nOldWidth, nWidth ), 0, |
663 | 0 | GetSizePixel().Width() , // the header is longer than the datawin |
664 | 0 | pDataWin->GetPosPixel().Y() - 1 ); |
665 | 0 | Control::Scroll( nWidth-nOldWidth, 0, aScrRect, SCROLL_FLAGS ); |
666 | 0 | aScrRect.SetBottom( pDataWin->GetSizePixel().Height() ); |
667 | 0 | pDataWin->Scroll( nWidth-nOldWidth, 0, aScrRect, SCROLL_FLAGS ); |
668 | 0 | tools::Rectangle aInvRect( nX, 0, nX + std::max( nWidth, nOldWidth ), USHRT_MAX ); |
669 | 0 | Control::Invalidate( aInvRect, InvalidateFlags::NoChildren ); |
670 | 0 | pDataWin->Invalidate( aInvRect ); |
671 | 0 | } |
672 | 0 | else |
673 | 0 | { |
674 | 0 | Control::Invalidate( InvalidateFlags::NoChildren ); |
675 | 0 | pDataWin->Window::Invalidate( InvalidateFlags::NoChildren ); |
676 | 0 | } |
677 | | |
678 | | |
679 | | //!pDataWin->Update(); |
680 | | //!Control::Update(); |
681 | 0 | bSelectionIsVisible = bSelVis; |
682 | 0 | ToggleSelection(); |
683 | 0 | DoShowCursor(); |
684 | 0 | } |
685 | 0 | UpdateScrollbars(); |
686 | | |
687 | | // adjust headerbar column |
688 | 0 | if ( pDataWin->pHeaderBar ) |
689 | 0 | pDataWin->pHeaderBar->SetItemSize( |
690 | 0 | nItemId ? nItemId : USHRT_MAX - 1, nWidth ); |
691 | | |
692 | | // adjust last column |
693 | 0 | if ( nItemPos != mvCols.size() - 1 ) |
694 | 0 | AutoSizeLastColumn(); |
695 | 0 | } |
696 | | |
697 | | |
698 | | void BrowseBox::AutoSizeLastColumn() |
699 | 0 | { |
700 | 0 | if ( pDataWin->bAutoSizeLastCol && |
701 | 0 | pDataWin->GetUpdateMode() ) |
702 | 0 | { |
703 | 0 | sal_uInt16 nId = GetColumnId( static_cast<sal_uInt16>(mvCols.size()) - 1 ); |
704 | 0 | SetColumnWidth( nId, LONG_MAX ); |
705 | 0 | ColumnResized( nId ); |
706 | 0 | } |
707 | 0 | } |
708 | | |
709 | | |
710 | | void BrowseBox::RemoveColumn( sal_uInt16 nItemId ) |
711 | 0 | { |
712 | | |
713 | | // get column position |
714 | 0 | sal_uInt16 nPos = GetColumnPos(nItemId); |
715 | 0 | if ( nPos >= ColCount() ) |
716 | | // not available |
717 | 0 | return; |
718 | | |
719 | | // correct column selection |
720 | 0 | if ( pColSel ) |
721 | 0 | pColSel->Remove( nPos ); |
722 | | |
723 | | // correct column cursor |
724 | 0 | if ( nCurColId == nItemId ) |
725 | 0 | nCurColId = 0; |
726 | | |
727 | | // delete column |
728 | 0 | mvCols.erase( mvCols.begin() + nPos ); |
729 | 0 | if ( nFirstCol >= nPos && nFirstCol > FrozenColCount() ) |
730 | 0 | { |
731 | 0 | OSL_ENSURE(nFirstCol > 0,"FirstCol must be greater zero!"); |
732 | 0 | --nFirstCol; |
733 | 0 | } |
734 | | |
735 | | // handlecolumn not in headerbar |
736 | 0 | if (nItemId) |
737 | 0 | { |
738 | 0 | if ( pDataWin->pHeaderBar ) |
739 | 0 | pDataWin->pHeaderBar->RemoveItem( nItemId ); |
740 | 0 | } |
741 | 0 | else |
742 | 0 | { |
743 | | // adjust headerbar |
744 | 0 | if ( pDataWin->pHeaderBar ) |
745 | 0 | { |
746 | 0 | pDataWin->pHeaderBar->SetPosSizePixel( |
747 | 0 | Point(0, 0), |
748 | 0 | Size( GetOutputSizePixel().Width(), GetTitleHeight() ) |
749 | 0 | ); |
750 | 0 | } |
751 | 0 | } |
752 | | |
753 | | // correct vertical scrollbar |
754 | 0 | UpdateScrollbars(); |
755 | | |
756 | | // trigger repaint, if necessary |
757 | 0 | if ( GetUpdateMode() ) |
758 | 0 | { |
759 | 0 | pDataWin->Invalidate(); |
760 | 0 | Control::Invalidate(); |
761 | 0 | if ( pDataWin->bAutoSizeLastCol && nPos ==ColCount() ) |
762 | 0 | SetColumnWidth( GetColumnId( nPos - 1 ), LONG_MAX ); |
763 | 0 | } |
764 | |
|
765 | 0 | if ( !isAccessibleAlive() ) |
766 | 0 | return; |
767 | | |
768 | 0 | commitTableEvent( |
769 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
770 | 0 | Any( AccessibleTableModelChange(COLUMNS_REMOVED, |
771 | 0 | -1, |
772 | 0 | -1, |
773 | 0 | nPos, |
774 | 0 | nPos |
775 | 0 | ) |
776 | 0 | ), |
777 | 0 | Any() |
778 | 0 | ); |
779 | |
|
780 | 0 | commitHeaderBarEvent( |
781 | 0 | AccessibleEventId::CHILD, |
782 | 0 | Any(), |
783 | 0 | Any( CreateAccessibleColumnHeader( nPos ) ), |
784 | 0 | true |
785 | 0 | ); |
786 | 0 | } |
787 | | |
788 | | |
789 | | void BrowseBox::RemoveColumns() |
790 | 0 | { |
791 | 0 | size_t nOldCount = mvCols.size(); |
792 | | |
793 | | // remove all columns |
794 | 0 | mvCols.clear(); |
795 | | |
796 | | // correct column selection |
797 | 0 | if ( pColSel ) |
798 | 0 | { |
799 | 0 | pColSel->SelectAll(false); |
800 | 0 | pColSel->SetTotalRange( Range( 0, 0 ) ); |
801 | 0 | } |
802 | | |
803 | | // correct column cursor |
804 | 0 | nCurColId = 0; |
805 | 0 | nFirstCol = 0; |
806 | |
|
807 | 0 | if ( pDataWin->pHeaderBar ) |
808 | 0 | pDataWin->pHeaderBar->Clear( ); |
809 | | |
810 | | // correct vertical scrollbar |
811 | 0 | UpdateScrollbars(); |
812 | | |
813 | | // trigger repaint if necessary |
814 | 0 | if ( GetUpdateMode() ) |
815 | 0 | { |
816 | 0 | pDataWin->Invalidate(); |
817 | 0 | Control::Invalidate(); |
818 | 0 | } |
819 | |
|
820 | 0 | if ( !isAccessibleAlive() ) |
821 | 0 | return; |
822 | | |
823 | 0 | if ( mvCols.size() == nOldCount ) |
824 | 0 | return; |
825 | | |
826 | | // all columns should be removed, so we remove the column header bar and append it again |
827 | | // to avoid to notify every column remove |
828 | 0 | commitBrowseBoxEvent( |
829 | 0 | AccessibleEventId::CHILD, |
830 | 0 | Any(), |
831 | 0 | Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar)) |
832 | 0 | ); |
833 | | |
834 | | // and now append it again |
835 | 0 | commitBrowseBoxEvent( |
836 | 0 | AccessibleEventId::CHILD, |
837 | 0 | Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar)), |
838 | 0 | Any() |
839 | 0 | ); |
840 | | |
841 | | // notify a table model change |
842 | 0 | commitTableEvent( |
843 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
844 | 0 | Any ( AccessibleTableModelChange( COLUMNS_REMOVED, |
845 | 0 | -1, |
846 | 0 | -1, |
847 | 0 | 0, |
848 | 0 | nOldCount |
849 | 0 | ) |
850 | 0 | ), |
851 | 0 | Any() |
852 | 0 | ); |
853 | 0 | } |
854 | | |
855 | | |
856 | | const OUString & BrowseBox::GetColumnTitle( sal_uInt16 nId ) const |
857 | 0 | { |
858 | |
|
859 | 0 | sal_uInt16 nItemPos = GetColumnPos( nId ); |
860 | 0 | if ( nItemPos >= mvCols.size() ) |
861 | 0 | return EMPTY_OUSTRING; |
862 | 0 | return mvCols[ nItemPos ]->Title(); |
863 | 0 | } |
864 | | |
865 | | sal_Int32 BrowseBox::GetRowCount() const |
866 | 0 | { |
867 | 0 | return nRowCount; |
868 | 0 | } |
869 | | |
870 | | sal_uInt16 BrowseBox::ColCount() const |
871 | 0 | { |
872 | 0 | return static_cast<sal_uInt16>(mvCols.size()); |
873 | 0 | } |
874 | | |
875 | | tools::Long BrowseBox::ImpGetDataRowHeight() const |
876 | 0 | { |
877 | 0 | BrowseBox *pThis = const_cast<BrowseBox*>(this); |
878 | 0 | pThis->m_nDataRowHeight = pThis->CalcReverseZoom(pDataWin->GetTextHeight() + 4); |
879 | 0 | pThis->Resize(); |
880 | 0 | pDataWin->Invalidate(); |
881 | 0 | return m_nDataRowHeight; |
882 | 0 | } |
883 | | |
884 | | void BrowseBox::SetDataRowHeight( tools::Long nPixel ) |
885 | 0 | { |
886 | |
|
887 | 0 | m_nDataRowHeight = CalcReverseZoom(nPixel); |
888 | 0 | Resize(); |
889 | 0 | pDataWin->Invalidate(); |
890 | 0 | } |
891 | | |
892 | | void BrowseBox::SetTitleLines( sal_uInt16 nLines ) |
893 | 0 | { |
894 | |
|
895 | 0 | nTitleLines = nLines; |
896 | 0 | } |
897 | | |
898 | | sal_Int32 BrowseBox::ScrollColumns( sal_Int32 nCols ) |
899 | 0 | { |
900 | |
|
901 | 0 | if ( nFirstCol + nCols < 0 || |
902 | 0 | o3tl::make_unsigned(nFirstCol + nCols) >= mvCols.size() ) |
903 | 0 | return 0; |
904 | | |
905 | | // implicitly hides cursor while scrolling |
906 | 0 | StartScroll(); |
907 | 0 | bScrolling = true; |
908 | 0 | bool bScrollable = pDataWin->GetBackground().IsScrollable(); |
909 | 0 | bool bInvalidateView = false; |
910 | | |
911 | | // scrolling one column to the right? |
912 | 0 | if ( nCols == 1 ) |
913 | 0 | { |
914 | | // update internal value and scrollbar |
915 | 0 | ++nFirstCol; |
916 | 0 | aHScroll->SetThumbPos( nFirstCol - FrozenColCount() ); |
917 | |
|
918 | 0 | if ( !bScrollable ) |
919 | 0 | { |
920 | 0 | bInvalidateView = true; |
921 | 0 | } |
922 | 0 | else |
923 | 0 | { |
924 | 0 | tools::Long nDelta = mvCols[ nFirstCol-1 ]->Width(); |
925 | 0 | tools::Long nFrozenWidth = GetFrozenWidth(); |
926 | |
|
927 | 0 | tools::Rectangle aScrollRect( Point( nFrozenWidth + nDelta, 0 ), |
928 | 0 | Size ( GetOutputSizePixel().Width() - nFrozenWidth - nDelta, |
929 | 0 | GetTitleHeight() - 1 |
930 | 0 | ) ); |
931 | | |
932 | | // scroll the header bar area (if there is no dedicated HeaderBar control) |
933 | 0 | if ( !pDataWin->pHeaderBar && nTitleLines ) |
934 | 0 | { |
935 | | // actually scroll |
936 | 0 | Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS ); |
937 | | |
938 | | // invalidate the area of the column which was scrolled out to the left hand side |
939 | 0 | tools::Rectangle aInvalidateRect( aScrollRect ); |
940 | 0 | aInvalidateRect.SetLeft( nFrozenWidth ); |
941 | 0 | aInvalidateRect.SetRight( nFrozenWidth + nDelta - 1 ); |
942 | 0 | Invalidate( aInvalidateRect ); |
943 | 0 | } |
944 | | |
945 | | // scroll the data-area |
946 | 0 | aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() ); |
947 | | |
948 | | // actually scroll |
949 | 0 | pDataWin->Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS ); |
950 | | |
951 | | // invalidate the area of the column which was scrolled out to the left hand side |
952 | 0 | aScrollRect.SetLeft( nFrozenWidth ); |
953 | 0 | aScrollRect.SetRight( nFrozenWidth + nDelta - 1 ); |
954 | 0 | pDataWin->Invalidate( aScrollRect ); |
955 | 0 | } |
956 | 0 | } |
957 | | |
958 | | // scrolling one column to the left? |
959 | 0 | else if ( nCols == -1 ) |
960 | 0 | { |
961 | 0 | --nFirstCol; |
962 | 0 | aHScroll->SetThumbPos( nFirstCol - FrozenColCount() ); |
963 | |
|
964 | 0 | if ( !bScrollable ) |
965 | 0 | { |
966 | 0 | bInvalidateView = true; |
967 | 0 | } |
968 | 0 | else |
969 | 0 | { |
970 | 0 | tools::Long nDelta = mvCols[ nFirstCol ]->Width(); |
971 | 0 | tools::Long nFrozenWidth = GetFrozenWidth(); |
972 | |
|
973 | 0 | tools::Rectangle aScrollRect( Point( nFrozenWidth, 0 ), |
974 | 0 | Size ( GetOutputSizePixel().Width() - nFrozenWidth, |
975 | 0 | GetTitleHeight() - 1 |
976 | 0 | ) ); |
977 | | |
978 | | // scroll the header bar area (if there is no dedicated HeaderBar control) |
979 | 0 | if ( !pDataWin->pHeaderBar && nTitleLines ) |
980 | 0 | { |
981 | 0 | Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS ); |
982 | 0 | } |
983 | | |
984 | | // scroll the data-area |
985 | 0 | aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() ); |
986 | 0 | pDataWin->Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS ); |
987 | 0 | } |
988 | 0 | } |
989 | 0 | else |
990 | 0 | { |
991 | 0 | if ( GetUpdateMode() ) |
992 | 0 | { |
993 | 0 | Invalidate( tools::Rectangle( |
994 | 0 | Point( GetFrozenWidth(), 0 ), |
995 | 0 | Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) ); |
996 | 0 | pDataWin->Invalidate( tools::Rectangle( |
997 | 0 | Point( GetFrozenWidth(), 0 ), |
998 | 0 | pDataWin->GetSizePixel() ) ); |
999 | 0 | } |
1000 | |
|
1001 | 0 | nFirstCol = nFirstCol + static_cast<sal_uInt16>(nCols); |
1002 | 0 | aHScroll->SetThumbPos( nFirstCol - FrozenColCount() ); |
1003 | 0 | } |
1004 | | |
1005 | | // adjust external headerbar, if necessary |
1006 | 0 | if ( pDataWin->pHeaderBar ) |
1007 | 0 | { |
1008 | 0 | tools::Long nWidth = 0; |
1009 | 0 | for ( size_t nCol = 0; |
1010 | 0 | nCol < mvCols.size() && nCol < nFirstCol; |
1011 | 0 | ++nCol ) |
1012 | 0 | { |
1013 | | // not the handle column |
1014 | 0 | if ( mvCols[ nCol ]->GetId() ) |
1015 | 0 | nWidth += mvCols[ nCol ]->Width(); |
1016 | 0 | } |
1017 | |
|
1018 | 0 | pDataWin->pHeaderBar->SetOffset( nWidth ); |
1019 | 0 | } |
1020 | |
|
1021 | 0 | if( bInvalidateView ) |
1022 | 0 | { |
1023 | 0 | Control::Invalidate( InvalidateFlags::NoChildren ); |
1024 | 0 | pDataWin->Window::Invalidate( InvalidateFlags::NoChildren ); |
1025 | 0 | } |
1026 | | |
1027 | | // implicitly show cursor after scrolling |
1028 | 0 | if ( nCols ) |
1029 | 0 | { |
1030 | 0 | pDataWin->Update(); |
1031 | 0 | PaintImmediately(); |
1032 | 0 | } |
1033 | 0 | bScrolling = false; |
1034 | 0 | EndScroll(); |
1035 | |
|
1036 | 0 | return nCols; |
1037 | 0 | } |
1038 | | |
1039 | | |
1040 | | sal_Int32 BrowseBox::ScrollRows( sal_Int32 nRows ) |
1041 | 0 | { |
1042 | | // compute new top row |
1043 | 0 | sal_Int32 nTmpMin = std::min( static_cast<sal_Int32>(nTopRow + nRows), static_cast<sal_Int32>(nRowCount - 1) ); |
1044 | |
|
1045 | 0 | sal_Int32 nNewTopRow = std::max<sal_Int32>( nTmpMin, 0 ); |
1046 | |
|
1047 | 0 | if ( nNewTopRow == nTopRow ) |
1048 | 0 | return 0; |
1049 | | |
1050 | 0 | sal_uInt16 nVisibleRows = |
1051 | 0 | static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1); |
1052 | |
|
1053 | 0 | VisibleRowsChanged(nNewTopRow, nVisibleRows); |
1054 | | |
1055 | | // compute new top row again (nTopRow might have changed!) |
1056 | 0 | nTmpMin = std::min( static_cast<tools::Long>(nTopRow + nRows), static_cast<tools::Long>(nRowCount - 1) ); |
1057 | |
|
1058 | 0 | nNewTopRow = std::max<tools::Long>( nTmpMin, 0 ); |
1059 | |
|
1060 | 0 | StartScroll(); |
1061 | | |
1062 | | // scroll area on screen and/or repaint |
1063 | 0 | tools::Long nDeltaY = GetDataRowHeight() * ( nNewTopRow - nTopRow ); |
1064 | 0 | sal_Int32 nOldTopRow = nTopRow; |
1065 | 0 | nTopRow = nNewTopRow; |
1066 | |
|
1067 | 0 | if ( GetUpdateMode() ) |
1068 | 0 | { |
1069 | 0 | pVScroll->SetRange( Range( 0L, nRowCount ) ); |
1070 | 0 | pVScroll->SetThumbPos( nTopRow ); |
1071 | |
|
1072 | 0 | if( pDataWin->GetBackground().IsScrollable() && |
1073 | 0 | std::abs( nDeltaY ) > 0 && |
1074 | 0 | std::abs( nDeltaY ) < pDataWin->GetSizePixel().Height() ) |
1075 | 0 | { |
1076 | 0 | pDataWin->Scroll( 0, static_cast<short>(-nDeltaY), SCROLL_FLAGS ); |
1077 | 0 | } |
1078 | 0 | else |
1079 | 0 | pDataWin->Invalidate(); |
1080 | |
|
1081 | 0 | if ( nTopRow - nOldTopRow ) |
1082 | 0 | pDataWin->Update(); |
1083 | 0 | } |
1084 | |
|
1085 | 0 | EndScroll(); |
1086 | |
|
1087 | 0 | return nTopRow - nOldTopRow; |
1088 | 0 | } |
1089 | | |
1090 | | |
1091 | | void BrowseBox::RowModified( sal_Int32 nRow, sal_uInt16 nColId ) |
1092 | 0 | { |
1093 | |
|
1094 | 0 | if ( !GetUpdateMode() ) |
1095 | 0 | return; |
1096 | | |
1097 | 0 | tools::Rectangle aRect; |
1098 | 0 | if ( nColId == BROWSER_INVALIDID ) |
1099 | | // invalidate the whole row |
1100 | 0 | aRect = tools::Rectangle( Point( 0, (nRow-nTopRow) * GetDataRowHeight() ), |
1101 | 0 | Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) ); |
1102 | 0 | else |
1103 | 0 | { |
1104 | | // invalidate the specific field |
1105 | 0 | aRect = GetFieldRectPixel( nRow, nColId, false ); |
1106 | 0 | } |
1107 | 0 | pDataWin->Invalidate( aRect ); |
1108 | 0 | } |
1109 | | |
1110 | | |
1111 | | void BrowseBox::Clear() |
1112 | 0 | { |
1113 | | // adjust the total number of rows |
1114 | 0 | DoHideCursor(); |
1115 | 0 | sal_Int32 nOldRowCount = nRowCount; |
1116 | 0 | nRowCount = 0; |
1117 | 0 | if(bMultiSelection) |
1118 | 0 | { |
1119 | 0 | assert(uRow.pSel); |
1120 | 0 | uRow.pSel->Reset(); |
1121 | 0 | } |
1122 | 0 | else |
1123 | 0 | uRow.nSel = BROWSER_ENDOFSELECTION; |
1124 | 0 | nCurRow = BROWSER_ENDOFSELECTION; |
1125 | 0 | nTopRow = 0; |
1126 | 0 | nCurColId = 0; |
1127 | | |
1128 | | // nFirstCol may not be reset, else the scrolling code will become confused. |
1129 | | // nFirstCol may only be changed when adding or deleting columns |
1130 | | // nFirstCol = 0; -> wrong! |
1131 | 0 | aHScroll->SetThumbPos( 0 ); |
1132 | 0 | pVScroll->SetThumbPos( 0 ); |
1133 | |
|
1134 | 0 | Invalidate(); |
1135 | 0 | UpdateScrollbars(); |
1136 | 0 | SetNoSelection(); |
1137 | 0 | DoShowCursor(); |
1138 | 0 | CursorMoved(); |
1139 | |
|
1140 | 0 | if ( !isAccessibleAlive() ) |
1141 | 0 | return; |
1142 | | |
1143 | | // all rows should be removed, so we remove the row header bar and append it again |
1144 | | // to avoid to notify every row remove |
1145 | 0 | if ( nOldRowCount == nRowCount ) |
1146 | 0 | return; |
1147 | | |
1148 | 0 | commitBrowseBoxEvent( |
1149 | 0 | AccessibleEventId::CHILD, |
1150 | 0 | Any(), |
1151 | 0 | Any(getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar)) |
1152 | 0 | ); |
1153 | | |
1154 | | // and now append it again |
1155 | 0 | commitBrowseBoxEvent( |
1156 | 0 | AccessibleEventId::CHILD, |
1157 | 0 | Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)), |
1158 | 0 | Any() |
1159 | 0 | ); |
1160 | | |
1161 | | // notify a table model change |
1162 | 0 | commitTableEvent( |
1163 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
1164 | 0 | Any( AccessibleTableModelChange(ROWS_REMOVED, |
1165 | 0 | 0, |
1166 | 0 | nOldRowCount, |
1167 | 0 | -1, |
1168 | 0 | -1) |
1169 | 0 | ), |
1170 | 0 | Any() |
1171 | 0 | ); |
1172 | 0 | } |
1173 | | |
1174 | | void BrowseBox::RowInserted( sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint, bool bKeepSelection ) |
1175 | 0 | { |
1176 | |
|
1177 | 0 | if (nRow < 0) |
1178 | 0 | nRow = 0; |
1179 | 0 | else if (nRow > nRowCount) // maximal = nRowCount |
1180 | 0 | nRow = nRowCount; |
1181 | |
|
1182 | 0 | if ( nNumRows <= 0 ) |
1183 | 0 | return; |
1184 | | |
1185 | | // adjust total row count |
1186 | 0 | bool bLastRow = nRow >= nRowCount; |
1187 | 0 | nRowCount += nNumRows; |
1188 | |
|
1189 | 0 | DoHideCursor(); |
1190 | | |
1191 | | // must we paint the new rows? |
1192 | 0 | sal_Int32 nOldCurRow = nCurRow; |
1193 | 0 | Size aSz = pDataWin->GetOutputSizePixel(); |
1194 | 0 | if ( bDoPaint && nRow >= nTopRow && |
1195 | 0 | nRow <= nTopRow + aSz.Height() / GetDataRowHeight() ) |
1196 | 0 | { |
1197 | 0 | tools::Long nY = (nRow-nTopRow) * GetDataRowHeight(); |
1198 | 0 | if ( !bLastRow ) |
1199 | 0 | { |
1200 | | // scroll down the rows behind the new row |
1201 | 0 | pDataWin->GetOutDev()->SetClipRegion(); |
1202 | 0 | if( pDataWin->GetBackground().IsScrollable() ) |
1203 | 0 | { |
1204 | 0 | pDataWin->Scroll( 0, GetDataRowHeight() * nNumRows, |
1205 | 0 | tools::Rectangle( Point( 0, nY ), |
1206 | 0 | Size( aSz.Width(), aSz.Height() - nY ) ), |
1207 | 0 | SCROLL_FLAGS ); |
1208 | 0 | } |
1209 | 0 | else |
1210 | 0 | pDataWin->Window::Invalidate( InvalidateFlags::NoChildren ); |
1211 | 0 | } |
1212 | 0 | else |
1213 | | // scroll would cause a repaint, so we must explicitly invalidate |
1214 | 0 | pDataWin->Invalidate( tools::Rectangle( Point( 0, nY ), |
1215 | 0 | Size( aSz.Width(), nNumRows * GetDataRowHeight() ) ) ); |
1216 | 0 | } |
1217 | | |
1218 | | // correct top row if necessary |
1219 | 0 | if ( nRow < nTopRow ) |
1220 | 0 | nTopRow += nNumRows; |
1221 | | |
1222 | | // adjust the selection |
1223 | 0 | if ( bMultiSelection ) |
1224 | 0 | uRow.pSel->Insert( nRow, nNumRows ); |
1225 | 0 | else if ( uRow.nSel != BROWSER_ENDOFSELECTION && nRow <= uRow.nSel ) |
1226 | 0 | uRow.nSel += nNumRows; |
1227 | | |
1228 | | // adjust the cursor |
1229 | 0 | if ( nCurRow == BROWSER_ENDOFSELECTION ) |
1230 | 0 | GoToRow( 0, false, bKeepSelection ); |
1231 | 0 | else if ( nRow <= nCurRow ) |
1232 | 0 | { |
1233 | 0 | nCurRow += nNumRows; |
1234 | 0 | GoToRow( nCurRow, false, bKeepSelection ); |
1235 | 0 | } |
1236 | | |
1237 | | // adjust the vertical scrollbar |
1238 | 0 | if ( bDoPaint ) |
1239 | 0 | { |
1240 | 0 | UpdateScrollbars(); |
1241 | 0 | AutoSizeLastColumn(); |
1242 | 0 | } |
1243 | |
|
1244 | 0 | DoShowCursor(); |
1245 | | // notify accessible that rows were inserted |
1246 | 0 | if ( isAccessibleAlive() ) |
1247 | 0 | { |
1248 | 0 | commitTableEvent( |
1249 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
1250 | 0 | Any( AccessibleTableModelChange( |
1251 | 0 | ROWS_INSERTED, |
1252 | 0 | nRow, |
1253 | 0 | nRow + nNumRows, |
1254 | 0 | -1, |
1255 | 0 | -1 |
1256 | 0 | ) |
1257 | 0 | ), |
1258 | 0 | Any() |
1259 | 0 | ); |
1260 | |
|
1261 | 0 | for (tools::Long i = nRow+1 ; i <= nRowCount ; ++i) |
1262 | 0 | { |
1263 | 0 | commitHeaderBarEvent( |
1264 | 0 | AccessibleEventId::CHILD, |
1265 | 0 | Any( CreateAccessibleRowHeader( i ) ), |
1266 | 0 | Any(), |
1267 | 0 | false |
1268 | 0 | ); |
1269 | 0 | } |
1270 | 0 | } |
1271 | |
|
1272 | 0 | if ( nCurRow != nOldCurRow ) |
1273 | 0 | CursorMoved(); |
1274 | |
|
1275 | 0 | DBG_ASSERT(nRowCount > 0,"BrowseBox: nRowCount <= 0"); |
1276 | 0 | DBG_ASSERT(nCurRow >= 0,"BrowseBox: nCurRow < 0"); |
1277 | 0 | DBG_ASSERT(nCurRow < nRowCount,"nCurRow >= nRowCount"); |
1278 | 0 | } |
1279 | | |
1280 | | |
1281 | | void BrowseBox::RowRemoved( sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint ) |
1282 | 0 | { |
1283 | |
|
1284 | 0 | if ( nRow < 0 ) |
1285 | 0 | nRow = 0; |
1286 | 0 | else if ( nRow >= nRowCount ) |
1287 | 0 | nRow = nRowCount - 1; |
1288 | |
|
1289 | 0 | if ( nNumRows <= 0 ) |
1290 | 0 | return; |
1291 | | |
1292 | 0 | if ( nRowCount <= 0 ) |
1293 | 0 | return; |
1294 | | |
1295 | 0 | if ( bDoPaint ) |
1296 | 0 | { |
1297 | | // hide cursor and selection |
1298 | 0 | SAL_INFO("svtools", "BrowseBox::HideCursor " << this ); |
1299 | 0 | ToggleSelection(); |
1300 | 0 | DoHideCursor(); |
1301 | 0 | } |
1302 | | |
1303 | | // adjust total row count |
1304 | 0 | nRowCount -= nNumRows; |
1305 | 0 | if (nRowCount < 0) nRowCount = 0; |
1306 | 0 | sal_Int32 nOldCurRow = nCurRow; |
1307 | | |
1308 | | // adjust the selection |
1309 | 0 | if ( bMultiSelection ) |
1310 | | // uRow.pSel->Remove( nRow, nNumRows ); |
1311 | 0 | for ( tools::Long i = 0; i < nNumRows; i++ ) |
1312 | 0 | uRow.pSel->Remove( nRow ); |
1313 | 0 | else if ( nRow < uRow.nSel && uRow.nSel >= nNumRows ) |
1314 | 0 | uRow.nSel -= nNumRows; |
1315 | 0 | else if ( nRow <= uRow.nSel ) |
1316 | 0 | uRow.nSel = BROWSER_ENDOFSELECTION; |
1317 | | |
1318 | | // adjust the cursor |
1319 | 0 | if ( nRowCount == 0 ) // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount |
1320 | 0 | nCurRow = BROWSER_ENDOFSELECTION; |
1321 | 0 | else if ( nRow < nCurRow ) |
1322 | 0 | { |
1323 | 0 | nCurRow -= std::min( nCurRow - nRow, nNumRows ); |
1324 | | // with the above nCurRow points a) to the first row after the removed block or b) to the same line |
1325 | | // as before, but moved up nNumRows |
1326 | | // case a) needs an additional correction if the last n lines were deleted, as 'the first row after the |
1327 | | // removed block' is an invalid position then |
1328 | | // FS - 09/28/99 - 68429 |
1329 | 0 | if (nCurRow == nRowCount) |
1330 | 0 | --nCurRow; |
1331 | 0 | } |
1332 | 0 | else if( nRow == nCurRow && nCurRow == nRowCount ) |
1333 | 0 | nCurRow = nRowCount-1; |
1334 | | |
1335 | | // is the deleted row visible? |
1336 | 0 | Size aSz = pDataWin->GetOutputSizePixel(); |
1337 | 0 | if ( nRow >= nTopRow && |
1338 | 0 | nRow <= nTopRow + aSz.Height() / GetDataRowHeight() ) |
1339 | 0 | { |
1340 | 0 | if ( bDoPaint ) |
1341 | 0 | { |
1342 | | // scroll up the rows behind the deleted row |
1343 | | // if there are Rows behind |
1344 | 0 | if (nRow < nRowCount) |
1345 | 0 | { |
1346 | 0 | tools::Long nY = (nRow-nTopRow) * GetDataRowHeight(); |
1347 | 0 | pDataWin->GetOutDev()->SetClipRegion(); |
1348 | 0 | if( pDataWin->GetBackground().IsScrollable() ) |
1349 | 0 | { |
1350 | 0 | pDataWin->Scroll( 0, - static_cast<short>(GetDataRowHeight()) * nNumRows, |
1351 | 0 | tools::Rectangle( Point( 0, nY ), Size( aSz.Width(), |
1352 | 0 | aSz.Height() - nY + nNumRows*GetDataRowHeight() ) ), |
1353 | 0 | SCROLL_FLAGS ); |
1354 | 0 | } |
1355 | 0 | else |
1356 | 0 | pDataWin->Window::Invalidate( InvalidateFlags::NoChildren ); |
1357 | 0 | } |
1358 | 0 | else |
1359 | 0 | { |
1360 | | // Repaint the Rect of the deleted row |
1361 | 0 | tools::Rectangle aRect( |
1362 | 0 | Point( 0, (nRow-nTopRow)*GetDataRowHeight() ), |
1363 | 0 | Size( pDataWin->GetSizePixel().Width(), |
1364 | 0 | nNumRows * GetDataRowHeight() ) ); |
1365 | 0 | pDataWin->Invalidate( aRect ); |
1366 | 0 | } |
1367 | 0 | } |
1368 | 0 | } |
1369 | | // is the deleted row above of the visible area? |
1370 | 0 | else if ( nRow < nTopRow ) |
1371 | 0 | nTopRow = nTopRow >= nNumRows ? nTopRow-nNumRows : 0; |
1372 | |
|
1373 | 0 | if ( bDoPaint ) |
1374 | 0 | { |
1375 | | // reshow cursor and selection |
1376 | 0 | ToggleSelection(); |
1377 | 0 | SAL_INFO("svtools", "BrowseBox::ShowCursor " << this ); |
1378 | 0 | DoShowCursor(); |
1379 | | |
1380 | | // adjust the vertical scrollbar |
1381 | 0 | UpdateScrollbars(); |
1382 | 0 | AutoSizeLastColumn(); |
1383 | 0 | } |
1384 | | |
1385 | 0 | if ( isAccessibleAlive() ) |
1386 | 0 | { |
1387 | 0 | if ( nRowCount == 0 ) |
1388 | 0 | { |
1389 | | // all columns should be removed, so we remove the column header bar and append it again |
1390 | | // to avoid to notify every column remove |
1391 | 0 | commitBrowseBoxEvent( |
1392 | 0 | AccessibleEventId::CHILD, |
1393 | 0 | Any(), |
1394 | 0 | Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)) |
1395 | 0 | ); |
1396 | | |
1397 | | // and now append it again |
1398 | 0 | commitBrowseBoxEvent( |
1399 | 0 | AccessibleEventId::CHILD, |
1400 | 0 | Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)), |
1401 | 0 | Any() |
1402 | 0 | ); |
1403 | 0 | commitBrowseBoxEvent( |
1404 | 0 | AccessibleEventId::CHILD, |
1405 | 0 | Any(), |
1406 | 0 | Any(getAccessibleTable()) |
1407 | 0 | ); |
1408 | | |
1409 | | // and now append it again |
1410 | 0 | commitBrowseBoxEvent( |
1411 | 0 | AccessibleEventId::CHILD, |
1412 | 0 | Any(getAccessibleTable()), |
1413 | 0 | Any() |
1414 | 0 | ); |
1415 | 0 | } |
1416 | 0 | else |
1417 | 0 | { |
1418 | 0 | commitTableEvent( |
1419 | 0 | AccessibleEventId::TABLE_MODEL_CHANGED, |
1420 | 0 | Any( AccessibleTableModelChange( |
1421 | 0 | ROWS_REMOVED, |
1422 | 0 | nRow, |
1423 | 0 | nRow + nNumRows, |
1424 | 0 | -1, |
1425 | 0 | -1 |
1426 | 0 | ) |
1427 | 0 | ), |
1428 | 0 | Any() |
1429 | 0 | ); |
1430 | |
|
1431 | 0 | for (tools::Long i = nRow+1 ; i <= (nRow+nNumRows) ; ++i) |
1432 | 0 | { |
1433 | 0 | commitHeaderBarEvent( |
1434 | 0 | AccessibleEventId::CHILD, |
1435 | 0 | Any(), |
1436 | 0 | Any( CreateAccessibleRowHeader( i ) ), |
1437 | 0 | false |
1438 | 0 | ); |
1439 | 0 | } |
1440 | 0 | } |
1441 | 0 | } |
1442 | |
|
1443 | 0 | if ( nOldCurRow != nCurRow ) |
1444 | 0 | CursorMoved(); |
1445 | |
|
1446 | 0 | DBG_ASSERT(nRowCount >= 0,"BrowseBox: nRowCount < 0"); |
1447 | 0 | DBG_ASSERT(nCurRow >= 0 || nRowCount == 0,"BrowseBox: nCurRow < 0 && nRowCount != 0"); |
1448 | 0 | DBG_ASSERT(nCurRow < nRowCount,"nCurRow >= nRowCount"); |
1449 | 0 | } |
1450 | | |
1451 | | |
1452 | | bool BrowseBox::GoToRow( sal_Int32 nRow) |
1453 | 0 | { |
1454 | 0 | return GoToRow(nRow, false); |
1455 | 0 | } |
1456 | | |
1457 | | |
1458 | | bool BrowseBox::GoToRow( sal_Int32 nRow, bool bRowColMove, bool bKeepSelection ) |
1459 | 0 | { |
1460 | 0 | sal_Int32 nOldCurRow = nCurRow; |
1461 | | |
1462 | | // nothing to do? |
1463 | 0 | if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) ) |
1464 | 0 | return true; |
1465 | | |
1466 | | // out of range? |
1467 | 0 | if ( nRow < 0 || nRow >= nRowCount ) |
1468 | 0 | return false; |
1469 | | |
1470 | | // not allowed? |
1471 | 0 | if ( !bRowColMove && !IsCursorMoveAllowed( nRow, nCurColId ) ) |
1472 | 0 | return false; |
1473 | | |
1474 | | // compute the last visible row |
1475 | 0 | Size aSz( pDataWin->GetSizePixel() ); |
1476 | 0 | sal_uInt16 nVisibleRows = sal_uInt16( aSz.Height() / GetDataRowHeight() - 1 ); |
1477 | 0 | sal_Int32 nLastRow = nTopRow + nVisibleRows; |
1478 | | |
1479 | | // suspend Updates |
1480 | 0 | pDataWin->EnterUpdateLock(); |
1481 | | |
1482 | | // remove old highlight, if necessary |
1483 | 0 | if ( !bMultiSelection && !bKeepSelection ) |
1484 | 0 | ToggleSelection(); |
1485 | 0 | DoHideCursor(); |
1486 | | |
1487 | | // must we scroll? |
1488 | 0 | bool bWasVisible = bSelectionIsVisible; |
1489 | 0 | if (! bMultiSelection) |
1490 | 0 | { |
1491 | 0 | if( !bKeepSelection ) |
1492 | 0 | bSelectionIsVisible = false; |
1493 | 0 | } |
1494 | 0 | if ( nRow < nTopRow ) |
1495 | 0 | ScrollRows( nRow - nTopRow ); |
1496 | 0 | else if ( nRow > nLastRow ) |
1497 | 0 | ScrollRows( nRow - nLastRow ); |
1498 | 0 | bSelectionIsVisible = bWasVisible; |
1499 | | |
1500 | | // adjust cursor (selection) and thumb |
1501 | 0 | if ( GetUpdateMode() ) |
1502 | 0 | pVScroll->SetThumbPos( nTopRow ); |
1503 | | |
1504 | | // relative positioning (because nCurRow might have changed in the meantime)! |
1505 | 0 | if (nCurRow != BROWSER_ENDOFSELECTION ) |
1506 | 0 | nCurRow = nCurRow + (nRow - nOldCurRow); |
1507 | | |
1508 | | // make sure that the current position is valid |
1509 | 0 | if (nCurRow == BROWSER_ENDOFSELECTION && nRowCount > 0) |
1510 | 0 | nCurRow = 0; |
1511 | 0 | else if ( nCurRow >= nRowCount ) |
1512 | 0 | nCurRow = nRowCount - 1; |
1513 | 0 | aSelRange = Range( nCurRow, nCurRow ); |
1514 | | |
1515 | | // display new highlight if necessary |
1516 | 0 | if ( !bMultiSelection && !bKeepSelection ) |
1517 | 0 | uRow.nSel = nRow; |
1518 | | |
1519 | | // resume Updates |
1520 | 0 | pDataWin->LeaveUpdateLock(); |
1521 | | |
1522 | | // Cursor+Highlight |
1523 | 0 | if ( !bMultiSelection && !bKeepSelection) |
1524 | 0 | ToggleSelection(); |
1525 | 0 | DoShowCursor(); |
1526 | 0 | if ( !bRowColMove && nOldCurRow != nCurRow ) |
1527 | 0 | CursorMoved(); |
1528 | |
|
1529 | 0 | if ( !bMultiSelection && !bKeepSelection ) |
1530 | 0 | { |
1531 | 0 | if ( !bSelecting ) |
1532 | 0 | Select(); |
1533 | 0 | else |
1534 | 0 | bSelect = true; |
1535 | 0 | } |
1536 | 0 | return true; |
1537 | 0 | } |
1538 | | |
1539 | | |
1540 | | bool BrowseBox::GoToColumnId( sal_uInt16 nColId) |
1541 | 0 | { |
1542 | 0 | return GoToColumnId(nColId, true); |
1543 | 0 | } |
1544 | | |
1545 | | |
1546 | | bool BrowseBox::GoToColumnId( sal_uInt16 nColId, bool bMakeVisible, bool bRowColMove) |
1547 | 0 | { |
1548 | 0 | if (!bColumnCursor) |
1549 | 0 | return false; |
1550 | | |
1551 | | // allowed? |
1552 | 0 | if (!bRowColMove && !IsCursorMoveAllowed( nCurRow, nColId ) ) |
1553 | 0 | return false; |
1554 | | |
1555 | 0 | if ( nColId != nCurColId || (bMakeVisible && !IsFieldVisible(nCurRow, nColId, true))) |
1556 | 0 | { |
1557 | 0 | sal_uInt16 nNewPos = GetColumnPos(nColId); |
1558 | 0 | BrowserColumn* pColumn = (nNewPos < mvCols.size()) ? mvCols[ nNewPos ].get() : nullptr; |
1559 | 0 | DBG_ASSERT( pColumn, "no column object - invalid id?" ); |
1560 | 0 | if ( !pColumn ) |
1561 | 0 | return false; |
1562 | | |
1563 | 0 | DoHideCursor(); |
1564 | 0 | nCurColId = nColId; |
1565 | |
|
1566 | 0 | bool bScrolled = false; |
1567 | |
|
1568 | 0 | sal_uInt16 nFirstPos = nFirstCol; |
1569 | 0 | sal_uInt16 nWidth = static_cast<sal_uInt16>(pColumn->Width()); |
1570 | 0 | sal_uInt16 nLastPos = GetColumnAtXPosPixel( |
1571 | 0 | pDataWin->GetSizePixel().Width()-nWidth ); |
1572 | 0 | sal_uInt16 nFrozen = FrozenColCount(); |
1573 | 0 | if ( bMakeVisible && nLastPos && |
1574 | 0 | nNewPos >= nFrozen && ( nNewPos < nFirstPos || nNewPos > nLastPos ) ) |
1575 | 0 | { |
1576 | 0 | if ( nNewPos < nFirstPos ) |
1577 | 0 | ScrollColumns( nNewPos-nFirstPos ); |
1578 | 0 | else if ( nNewPos > nLastPos ) |
1579 | 0 | ScrollColumns( nNewPos-nLastPos ); |
1580 | 0 | bScrolled = true; |
1581 | 0 | } |
1582 | |
|
1583 | 0 | DoShowCursor(); |
1584 | 0 | if (!bRowColMove) |
1585 | 0 | { |
1586 | | //try to move to nCurRow, nColId |
1587 | 0 | CursorMoveAttempt aAttempt(nCurRow, nColId, bScrolled); |
1588 | | //Detect if we are already in a call to BrowseBox::GoToColumnId |
1589 | | //but the attempt is impossible and we are simply recursing |
1590 | | //into BrowseBox::GoToColumnId with the same impossible to |
1591 | | //fulfill conditions |
1592 | 0 | if (m_aGotoStack.empty() || aAttempt != m_aGotoStack.top()) |
1593 | 0 | { |
1594 | 0 | m_aGotoStack.push(aAttempt); |
1595 | 0 | CursorMoved(); |
1596 | 0 | m_aGotoStack.pop(); |
1597 | 0 | } |
1598 | 0 | } |
1599 | 0 | return true; |
1600 | 0 | } |
1601 | 0 | return true; |
1602 | 0 | } |
1603 | | |
1604 | | |
1605 | | bool BrowseBox::GoToRowColumnId( sal_Int32 nRow, sal_uInt16 nColId ) |
1606 | 0 | { |
1607 | | |
1608 | | // out of range? |
1609 | 0 | if ( nRow < 0 || nRow >= nRowCount ) |
1610 | 0 | return false; |
1611 | | |
1612 | 0 | if (!bColumnCursor) |
1613 | 0 | return false; |
1614 | | |
1615 | | // nothing to do ? |
1616 | 0 | if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) && |
1617 | 0 | nColId == nCurColId && IsFieldVisible(nCurRow, nColId, true)) |
1618 | 0 | return true; |
1619 | | |
1620 | | // allowed? |
1621 | 0 | if (!IsCursorMoveAllowed(nRow, nColId)) |
1622 | 0 | return false; |
1623 | | |
1624 | 0 | DoHideCursor(); |
1625 | 0 | bool bMoved = GoToRow(nRow, true) && GoToColumnId(nColId, true, true); |
1626 | 0 | DoShowCursor(); |
1627 | |
|
1628 | 0 | if (bMoved) |
1629 | 0 | CursorMoved(); |
1630 | |
|
1631 | 0 | return bMoved; |
1632 | 0 | } |
1633 | | |
1634 | | |
1635 | | void BrowseBox::SetNoSelection() |
1636 | 0 | { |
1637 | | |
1638 | | // is there no selection |
1639 | 0 | if ( ( !pColSel || !pColSel->GetSelectCount() ) && |
1640 | 0 | ( ( !bMultiSelection && uRow.nSel == BROWSER_ENDOFSELECTION ) || |
1641 | 0 | ( bMultiSelection && !uRow.pSel->GetSelectCount() ) ) ) |
1642 | | // nothing to do |
1643 | 0 | return; |
1644 | | |
1645 | 0 | SAL_INFO("svtools", "BrowseBox::HideCursor " << this ); |
1646 | 0 | ToggleSelection(); |
1647 | | |
1648 | | // unselect all |
1649 | 0 | if ( bMultiSelection ) |
1650 | 0 | uRow.pSel->SelectAll(false); |
1651 | 0 | else |
1652 | 0 | uRow.nSel = BROWSER_ENDOFSELECTION; |
1653 | 0 | if ( pColSel ) |
1654 | 0 | pColSel->SelectAll(false); |
1655 | 0 | if ( !bSelecting ) |
1656 | 0 | Select(); |
1657 | 0 | else |
1658 | 0 | bSelect = true; |
1659 | | |
1660 | | // restore screen |
1661 | 0 | SAL_INFO("svtools", "BrowseBox::ShowCursor " << this ); |
1662 | | |
1663 | 0 | if ( isAccessibleAlive() ) |
1664 | 0 | { |
1665 | 0 | commitTableEvent( |
1666 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1667 | 0 | Any(), |
1668 | 0 | Any() |
1669 | 0 | ); |
1670 | 0 | } |
1671 | 0 | } |
1672 | | |
1673 | | |
1674 | | void BrowseBox::SelectAll() |
1675 | 0 | { |
1676 | |
|
1677 | 0 | if ( !bMultiSelection ) |
1678 | 0 | return; |
1679 | | |
1680 | 0 | SAL_INFO("svtools", "BrowseBox::HideCursor " << this ); |
1681 | 0 | ToggleSelection(); |
1682 | | |
1683 | | // select all rows |
1684 | 0 | if ( pColSel ) |
1685 | 0 | pColSel->SelectAll(false); |
1686 | 0 | uRow.pSel->SelectAll(); |
1687 | | |
1688 | | // don't highlight handle column |
1689 | 0 | BrowserColumn *pFirstCol = mvCols[ 0 ].get(); |
1690 | 0 | tools::Long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width(); |
1691 | | |
1692 | | // highlight the row selection |
1693 | 0 | if ( !bHideSelect ) |
1694 | 0 | { |
1695 | 0 | tools::Rectangle aHighlightRect; |
1696 | 0 | sal_uInt16 nVisibleRows = |
1697 | 0 | static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1); |
1698 | 0 | for ( sal_Int32 nRow = std::max<sal_Int32>( nTopRow, uRow.pSel->FirstSelected() ); |
1699 | 0 | nRow != BROWSER_ENDOFSELECTION && nRow < nTopRow + nVisibleRows; |
1700 | 0 | nRow = uRow.pSel->NextSelected() ) |
1701 | 0 | aHighlightRect.Union( tools::Rectangle( |
1702 | 0 | Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ), |
1703 | 0 | Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) ) ); |
1704 | 0 | pDataWin->Invalidate( aHighlightRect ); |
1705 | 0 | } |
1706 | |
|
1707 | 0 | if ( !bSelecting ) |
1708 | 0 | Select(); |
1709 | 0 | else |
1710 | 0 | bSelect = true; |
1711 | | |
1712 | | // restore screen |
1713 | 0 | SAL_INFO("svtools", "BrowseBox::ShowCursor " << this ); |
1714 | | |
1715 | 0 | if ( !isAccessibleAlive() ) |
1716 | 0 | return; |
1717 | | |
1718 | 0 | commitTableEvent( |
1719 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1720 | 0 | Any(), |
1721 | 0 | Any() |
1722 | 0 | ); |
1723 | 0 | commitHeaderBarEvent( |
1724 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1725 | 0 | Any(), |
1726 | 0 | Any(), |
1727 | 0 | true |
1728 | 0 | ); // column header event |
1729 | |
|
1730 | 0 | commitHeaderBarEvent( |
1731 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1732 | 0 | Any(), |
1733 | 0 | Any(), |
1734 | 0 | false |
1735 | 0 | ); // row header event |
1736 | 0 | } |
1737 | | |
1738 | | |
1739 | | void BrowseBox::SelectRow( sal_Int32 nRow, bool _bSelect, bool bExpand ) |
1740 | 0 | { |
1741 | |
|
1742 | 0 | if ( !bMultiSelection ) |
1743 | 0 | { |
1744 | | // deselecting is impossible, selecting via cursor |
1745 | 0 | if ( _bSelect ) |
1746 | 0 | GoToRow(nRow, false); |
1747 | 0 | return; |
1748 | 0 | } |
1749 | | |
1750 | 0 | SAL_INFO("svtools", "BrowseBox::HideCursor " << this ); |
1751 | | |
1752 | | // remove old selection? |
1753 | 0 | if ( !bExpand || !bMultiSelection ) |
1754 | 0 | { |
1755 | 0 | ToggleSelection(); |
1756 | 0 | if ( bMultiSelection ) |
1757 | 0 | uRow.pSel->SelectAll(false); |
1758 | 0 | else |
1759 | 0 | uRow.nSel = BROWSER_ENDOFSELECTION; |
1760 | 0 | if ( pColSel ) |
1761 | 0 | pColSel->SelectAll(false); |
1762 | 0 | } |
1763 | | |
1764 | | // set new selection |
1765 | 0 | if ( !bHideSelect |
1766 | 0 | && ( ( bMultiSelection |
1767 | 0 | && uRow.pSel->GetTotalRange().Max() >= nRow |
1768 | 0 | && uRow.pSel->Select( nRow, _bSelect ) |
1769 | 0 | ) |
1770 | 0 | || ( !bMultiSelection |
1771 | 0 | && ( uRow.nSel = nRow ) != BROWSER_ENDOFSELECTION ) |
1772 | 0 | ) |
1773 | 0 | ) |
1774 | 0 | { |
1775 | | // don't highlight handle column |
1776 | 0 | BrowserColumn *pFirstCol = mvCols[ 0 ].get(); |
1777 | 0 | tools::Long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width(); |
1778 | | |
1779 | | // highlight only newly selected part |
1780 | 0 | tools::Rectangle aRect( |
1781 | 0 | Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ), |
1782 | 0 | Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) ); |
1783 | 0 | pDataWin->Invalidate( aRect ); |
1784 | 0 | } |
1785 | |
|
1786 | 0 | if ( !bSelecting ) |
1787 | 0 | Select(); |
1788 | 0 | else |
1789 | 0 | bSelect = true; |
1790 | | |
1791 | | // restore screen |
1792 | 0 | SAL_INFO("svtools", "BrowseBox::ShowCursor " << this ); |
1793 | | |
1794 | 0 | if ( !isAccessibleAlive() ) |
1795 | 0 | return; |
1796 | | |
1797 | 0 | commitTableEvent( |
1798 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1799 | 0 | Any(), |
1800 | 0 | Any() |
1801 | 0 | ); |
1802 | 0 | commitHeaderBarEvent( |
1803 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1804 | 0 | Any(), |
1805 | 0 | Any(), |
1806 | 0 | false |
1807 | 0 | ); // row header event |
1808 | 0 | } |
1809 | | |
1810 | | |
1811 | | sal_Int32 BrowseBox::GetSelectRowCount() const |
1812 | 0 | { |
1813 | |
|
1814 | 0 | return bMultiSelection ? uRow.pSel->GetSelectCount() : |
1815 | 0 | uRow.nSel == BROWSER_ENDOFSELECTION ? 0 : 1; |
1816 | 0 | } |
1817 | | |
1818 | | |
1819 | | void BrowseBox::SelectColumnPos( sal_uInt16 nNewColPos, bool _bSelect, bool bMakeVisible ) |
1820 | 0 | { |
1821 | |
|
1822 | 0 | if ( !bColumnCursor || nNewColPos == BROWSER_INVALIDID ) |
1823 | 0 | return; |
1824 | | |
1825 | 0 | if ( !bMultiSelection ) |
1826 | 0 | { |
1827 | 0 | if ( _bSelect ) |
1828 | 0 | GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible ); |
1829 | 0 | return; |
1830 | 0 | } |
1831 | 0 | else |
1832 | 0 | { |
1833 | 0 | if ( !GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible ) ) |
1834 | 0 | return; |
1835 | 0 | } |
1836 | | |
1837 | 0 | SAL_INFO("svtools", "BrowseBox::HideCursor " << this ); |
1838 | 0 | ToggleSelection(); |
1839 | 0 | if ( bMultiSelection ) |
1840 | 0 | uRow.pSel->SelectAll(false); |
1841 | 0 | else |
1842 | 0 | uRow.nSel = BROWSER_ENDOFSELECTION; |
1843 | 0 | pColSel->SelectAll(false); |
1844 | |
|
1845 | 0 | if ( pColSel->Select( nNewColPos, _bSelect ) ) |
1846 | 0 | { |
1847 | | // GoToColumnId( mvCols->GetObject(nNewColPos)->GetId(), bMakeVisible ); |
1848 | | |
1849 | | // only highlight painted areas |
1850 | 0 | pDataWin->Update(); |
1851 | 0 | tools::Rectangle aFieldRectPix( GetFieldRectPixel( nCurRow, nCurColId, false ) ); |
1852 | 0 | tools::Rectangle aRect( |
1853 | 0 | Point( aFieldRectPix.Left() - MIN_COLUMNWIDTH, 0 ), |
1854 | 0 | Size( mvCols[ nNewColPos ]->Width(), |
1855 | 0 | pDataWin->GetOutputSizePixel().Height() ) ); |
1856 | 0 | pDataWin->Invalidate( aRect ); |
1857 | 0 | if ( !bSelecting ) |
1858 | 0 | Select(); |
1859 | 0 | else |
1860 | 0 | bSelect = true; |
1861 | |
|
1862 | 0 | if ( isAccessibleAlive() ) |
1863 | 0 | { |
1864 | 0 | commitTableEvent( |
1865 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1866 | 0 | Any(), |
1867 | 0 | Any() |
1868 | 0 | ); |
1869 | 0 | commitHeaderBarEvent( |
1870 | 0 | AccessibleEventId::SELECTION_CHANGED, |
1871 | 0 | Any(), |
1872 | 0 | Any(), |
1873 | 0 | true |
1874 | 0 | ); // column header event |
1875 | 0 | } |
1876 | 0 | } |
1877 | | |
1878 | | // restore screen |
1879 | 0 | SAL_INFO("svtools", "BrowseBox::ShowCursor " << this ); |
1880 | 0 | } |
1881 | | |
1882 | | |
1883 | | sal_uInt16 BrowseBox::GetSelectColumnCount() const |
1884 | 0 | { |
1885 | | |
1886 | | // while bAutoSelect (==!pColSel), 1 if any rows (yes rows!) else none |
1887 | 0 | return pColSel ? static_cast<sal_uInt16>(pColSel->GetSelectCount()) : |
1888 | 0 | nCurRow >= 0 ? 1 : 0; |
1889 | 0 | } |
1890 | | |
1891 | | |
1892 | | sal_Int32 BrowseBox::FirstSelectedColumn( ) const |
1893 | 0 | { |
1894 | 0 | return pColSel ? pColSel->FirstSelected() : BROWSER_ENDOFSELECTION; |
1895 | 0 | } |
1896 | | |
1897 | | |
1898 | | sal_Int32 BrowseBox::FirstSelectedRow() |
1899 | 0 | { |
1900 | |
|
1901 | 0 | return bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel; |
1902 | 0 | } |
1903 | | |
1904 | | |
1905 | | sal_Int32 BrowseBox::NextSelectedRow() |
1906 | 0 | { |
1907 | |
|
1908 | 0 | return bMultiSelection ? uRow.pSel->NextSelected() : BROWSER_ENDOFSELECTION; |
1909 | 0 | } |
1910 | | |
1911 | | |
1912 | | sal_Int32 BrowseBox::LastSelectedRow() |
1913 | 0 | { |
1914 | |
|
1915 | 0 | return bMultiSelection ? uRow.pSel->LastSelected() : uRow.nSel; |
1916 | 0 | } |
1917 | | |
1918 | | |
1919 | | bool BrowseBox::IsRowSelected( sal_Int32 nRow ) const |
1920 | 0 | { |
1921 | |
|
1922 | 0 | return bMultiSelection ? uRow.pSel->IsSelected(nRow) : nRow == uRow.nSel; |
1923 | 0 | } |
1924 | | |
1925 | | |
1926 | | bool BrowseBox::IsColumnSelected( sal_uInt16 nColumnId ) const |
1927 | 0 | { |
1928 | |
|
1929 | 0 | return pColSel ? pColSel->IsSelected( GetColumnPos(nColumnId) ) : |
1930 | 0 | nCurColId == nColumnId; |
1931 | 0 | } |
1932 | | |
1933 | | |
1934 | | void BrowseBox::MakeFieldVisible |
1935 | | ( |
1936 | | sal_Int32 nRow, // line number of the field (starting with 0) |
1937 | | sal_uInt16 nColId // column ID of the field |
1938 | | ) |
1939 | | |
1940 | | /* [Description] |
1941 | | |
1942 | | Makes visible the field described in 'nRow' and 'nColId' by scrolling |
1943 | | accordingly. |
1944 | | |
1945 | | */ |
1946 | | |
1947 | 0 | { |
1948 | 0 | if (!pDataWin) |
1949 | 0 | return; |
1950 | | |
1951 | 0 | Size aTestSize = pDataWin->GetSizePixel(); |
1952 | |
|
1953 | 0 | if ( !bBootstrapped || aTestSize.IsEmpty() ) |
1954 | 0 | return; |
1955 | | |
1956 | | // is it visible already? |
1957 | 0 | bool bVisible = IsFieldVisible( nRow, nColId, true/*bComplete*/ ); |
1958 | 0 | if ( bVisible ) |
1959 | 0 | return; |
1960 | | |
1961 | | // calculate column position, field rectangle and painting area |
1962 | 0 | sal_uInt16 nColPos = GetColumnPos( nColId ); |
1963 | 0 | tools::Rectangle aFieldRect = GetFieldRectPixel( nRow, nColId, false ); |
1964 | 0 | tools::Rectangle aDataRect( Point(0, 0), pDataWin->GetSizePixel() ); |
1965 | | |
1966 | | // positioned outside on the left? |
1967 | 0 | if ( nColPos >= FrozenColCount() && nColPos < nFirstCol ) |
1968 | | // => scroll to the right |
1969 | 0 | ScrollColumns( nColPos - nFirstCol ); |
1970 | | |
1971 | | // while outside on the right |
1972 | 0 | while ( aDataRect.Right() < aFieldRect.Right() ) |
1973 | 0 | { |
1974 | | // => scroll to the left |
1975 | 0 | if ( ScrollColumns( 1 ) != 1 ) |
1976 | | // no more need to scroll |
1977 | 0 | break; |
1978 | 0 | aFieldRect = GetFieldRectPixel( nRow, nColId, false ); |
1979 | 0 | } |
1980 | | |
1981 | | // positioned outside above? |
1982 | 0 | if ( nRow < nTopRow ) |
1983 | | // scroll further to the bottom |
1984 | 0 | ScrollRows( nRow - nTopRow ); |
1985 | | |
1986 | | // positioned outside below? |
1987 | 0 | sal_Int32 nBottomRow = nTopRow + GetVisibleRows(); |
1988 | | // decrement nBottomRow to make it the number of the last visible line |
1989 | | // (count starts with 0!). |
1990 | | // Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1 |
1991 | 0 | if( nBottomRow ) |
1992 | 0 | nBottomRow--; |
1993 | |
|
1994 | 0 | if ( nRow > nBottomRow ) |
1995 | | // scroll further to the top |
1996 | 0 | ScrollRows( nRow - nBottomRow ); |
1997 | 0 | } |
1998 | | |
1999 | | |
2000 | | bool BrowseBox::IsFieldVisible( sal_Int32 nRow, sal_uInt16 nColumnId, |
2001 | | bool bCompletely ) const |
2002 | 0 | { |
2003 | | |
2004 | | // hidden by frozen column? |
2005 | 0 | sal_uInt16 nColPos = GetColumnPos( nColumnId ); |
2006 | 0 | if ( nColPos >= FrozenColCount() && nColPos < nFirstCol ) |
2007 | 0 | return false; |
2008 | | |
2009 | 0 | tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) ); |
2010 | 0 | if ( aRect.IsEmpty() ) |
2011 | 0 | return false; |
2012 | | |
2013 | | // get the visible area |
2014 | 0 | tools::Rectangle aOutRect( Point(0, 0), pDataWin->GetOutputSizePixel() ); |
2015 | |
|
2016 | 0 | if ( bCompletely ) |
2017 | | // test if the field is completely visible |
2018 | 0 | return aOutRect.Contains( aRect ); |
2019 | 0 | else |
2020 | | // test if the field is partly of completely visible |
2021 | 0 | return !aOutRect.Intersection( aRect ).IsEmpty(); |
2022 | 0 | } |
2023 | | |
2024 | | |
2025 | | tools::Rectangle BrowseBox::GetFieldRectPixel( sal_Int32 nRow, sal_uInt16 nColumnId, |
2026 | | bool bRelToBrowser) const |
2027 | 0 | { |
2028 | | |
2029 | | // get the rectangle relative to DataWin |
2030 | 0 | tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) ); |
2031 | 0 | if ( aRect.IsEmpty() ) |
2032 | 0 | return aRect; |
2033 | | |
2034 | | // adjust relative to BrowseBox's output area |
2035 | 0 | Point aTopLeft( aRect.TopLeft() ); |
2036 | 0 | if ( bRelToBrowser ) |
2037 | 0 | { |
2038 | 0 | aTopLeft = pDataWin->OutputToScreenPixel( aTopLeft ); |
2039 | 0 | aTopLeft = ScreenToOutputPixel( aTopLeft ); |
2040 | 0 | } |
2041 | |
|
2042 | 0 | return tools::Rectangle( aTopLeft, aRect.GetSize() ); |
2043 | 0 | } |
2044 | | |
2045 | | |
2046 | | tools::Rectangle BrowseBox::GetRowRectPixel( sal_Int32 nRow ) const |
2047 | 0 | { |
2048 | | |
2049 | | // get the rectangle relative to DataWin |
2050 | 0 | tools::Rectangle aRect; |
2051 | 0 | if ( nTopRow > nRow ) |
2052 | | // row is above visible area |
2053 | 0 | return aRect; |
2054 | 0 | aRect = tools::Rectangle( |
2055 | 0 | Point( 0, GetDataRowHeight() * (nRow-nTopRow) ), |
2056 | 0 | Size( pDataWin->GetOutputSizePixel().Width(), GetDataRowHeight() ) ); |
2057 | 0 | if ( aRect.Top() > pDataWin->GetOutputSizePixel().Height() ) |
2058 | | // row is below visible area |
2059 | 0 | return aRect; |
2060 | | |
2061 | | // adjust relative to BrowseBox's output area |
2062 | 0 | Point aTopLeft( aRect.TopLeft() ); |
2063 | 0 | aTopLeft = pDataWin->OutputToScreenPixel( aTopLeft ); |
2064 | 0 | aTopLeft = ScreenToOutputPixel( aTopLeft ); |
2065 | |
|
2066 | 0 | return tools::Rectangle( aTopLeft, aRect.GetSize() ); |
2067 | 0 | } |
2068 | | |
2069 | | |
2070 | | tools::Rectangle BrowseBox::ImplFieldRectPixel( sal_Int32 nRow, sal_uInt16 nColumnId ) const |
2071 | 0 | { |
2072 | | |
2073 | | // compute the X-coordinate relative to DataWin by accumulation |
2074 | 0 | tools::Long nColX = 0; |
2075 | 0 | sal_uInt16 nFrozenCols = FrozenColCount(); |
2076 | 0 | size_t nCol; |
2077 | 0 | for ( nCol = 0; |
2078 | 0 | nCol < mvCols.size() && mvCols[ nCol ]->GetId() != nColumnId; |
2079 | 0 | ++nCol ) |
2080 | 0 | if ( mvCols[ nCol ]->IsFrozen() || nCol >= nFirstCol ) |
2081 | 0 | nColX += mvCols[ nCol ]->Width(); |
2082 | |
|
2083 | 0 | if ( nCol >= mvCols.size() || ( nCol >= nFrozenCols && nCol < nFirstCol ) ) |
2084 | 0 | return tools::Rectangle(); |
2085 | | |
2086 | | // compute the Y-coordinate relative to DataWin |
2087 | 0 | tools::Long nRowY = GetDataRowHeight(); |
2088 | 0 | if ( nRow != BROWSER_ENDOFSELECTION ) // #105497# OJ |
2089 | 0 | nRowY = ( nRow - nTopRow ) * GetDataRowHeight(); |
2090 | | |
2091 | | // assemble the Rectangle relative to DataWin |
2092 | 0 | return tools::Rectangle( |
2093 | 0 | Point( nColX + MIN_COLUMNWIDTH, nRowY ), |
2094 | 0 | Size( (mvCols[nCol]->Width() == LONG_MAX |
2095 | 0 | ? LONG_MAX - (nColX + MIN_COLUMNWIDTH) : mvCols[ nCol ]->Width() - 2*MIN_COLUMNWIDTH), |
2096 | 0 | GetDataRowHeight() - 1 ) ); |
2097 | 0 | } |
2098 | | |
2099 | | |
2100 | | sal_Int32 BrowseBox::GetRowAtYPosPixel( tools::Long nY, bool bRelToBrowser ) const |
2101 | 0 | { |
2102 | | |
2103 | | // compute the Y-coordinate |
2104 | 0 | if ( bRelToBrowser ) |
2105 | 0 | { |
2106 | 0 | Point aDataTopLeft = pDataWin->OutputToScreenPixel( Point(0, 0) ); |
2107 | 0 | Point aTopLeft = OutputToScreenPixel( Point(0, 0) ); |
2108 | 0 | nY -= aDataTopLeft.Y() - aTopLeft.Y(); |
2109 | 0 | } |
2110 | | |
2111 | | // no row there (e.g. in the header) |
2112 | 0 | if ( nY < 0 || nY >= pDataWin->GetOutputSizePixel().Height() ) |
2113 | 0 | return -1; |
2114 | | |
2115 | 0 | return nY / GetDataRowHeight() + nTopRow; |
2116 | 0 | } |
2117 | | |
2118 | | |
2119 | | tools::Rectangle BrowseBox::GetFieldRect( sal_uInt16 nColumnId ) const |
2120 | 0 | { |
2121 | |
|
2122 | 0 | return GetFieldRectPixel( nCurRow, nColumnId ); |
2123 | 0 | } |
2124 | | |
2125 | | |
2126 | | sal_uInt16 BrowseBox::GetColumnAtXPosPixel( tools::Long nX ) const |
2127 | 0 | { |
2128 | | |
2129 | | // accumulate the widths of the visible columns |
2130 | 0 | tools::Long nColX = 0; |
2131 | 0 | for ( size_t nCol = 0; nCol < mvCols.size(); ++nCol ) |
2132 | 0 | { |
2133 | 0 | BrowserColumn *pCol = mvCols[ nCol ].get(); |
2134 | 0 | if ( pCol->IsFrozen() || nCol >= nFirstCol ) |
2135 | 0 | nColX += pCol->Width(); |
2136 | |
|
2137 | 0 | if ( nColX > nX ) |
2138 | 0 | return nCol; |
2139 | 0 | } |
2140 | | |
2141 | 0 | return BROWSER_INVALIDID; |
2142 | 0 | } |
2143 | | |
2144 | | bool BrowseBox::ReserveControlArea(sal_uInt16 nWidth) |
2145 | 0 | { |
2146 | 0 | if (nWidth != nControlAreaWidth) |
2147 | 0 | { |
2148 | 0 | OSL_ENSURE(nWidth,"Control area of 0 is not allowed, Use USHRT_MAX instead!"); |
2149 | 0 | nControlAreaWidth = nWidth; |
2150 | 0 | UpdateScrollbars(); |
2151 | 0 | return true; |
2152 | 0 | } |
2153 | 0 | return false; |
2154 | 0 | } |
2155 | | |
2156 | | tools::Rectangle BrowseBox::GetControlArea() const |
2157 | 0 | { |
2158 | 0 | auto nHeight = aHScroll->GetSizePixel().Height(); |
2159 | 0 | auto nEndRight = aHScroll->GetPosPixel().X(); |
2160 | |
|
2161 | 0 | return tools::Rectangle( |
2162 | 0 | Point( 0, GetOutputSizePixel().Height() - nHeight ), |
2163 | 0 | Size( nEndRight, nHeight ) ); |
2164 | 0 | } |
2165 | | |
2166 | | void BrowseBox::SetMode( BrowserMode nMode ) |
2167 | 0 | { |
2168 | |
|
2169 | 0 | pDataWin->bAutoHScroll = BrowserMode::AUTO_HSCROLL == ( nMode & BrowserMode::AUTO_HSCROLL ); |
2170 | 0 | pDataWin->bAutoVScroll = BrowserMode::AUTO_VSCROLL == ( nMode & BrowserMode::AUTO_VSCROLL ); |
2171 | 0 | pDataWin->bNoHScroll = BrowserMode::NO_HSCROLL == ( nMode & BrowserMode::NO_HSCROLL ); |
2172 | 0 | pDataWin->bNoVScroll = BrowserMode::NO_VSCROLL == ( nMode & BrowserMode::NO_VSCROLL ); |
2173 | |
|
2174 | 0 | DBG_ASSERT( !( pDataWin->bAutoHScroll && pDataWin->bNoHScroll ), |
2175 | 0 | "BrowseBox::SetMode: AutoHScroll *and* NoHScroll?" ); |
2176 | 0 | DBG_ASSERT( !( pDataWin->bAutoVScroll && pDataWin->bNoVScroll ), |
2177 | 0 | "BrowseBox::SetMode: AutoVScroll *and* NoVScroll?" ); |
2178 | 0 | if ( pDataWin->bAutoHScroll ) |
2179 | 0 | pDataWin->bNoHScroll = false; |
2180 | 0 | if ( pDataWin->bAutoVScroll ) |
2181 | 0 | pDataWin->bNoVScroll = false; |
2182 | |
|
2183 | 0 | if ( pDataWin->bNoHScroll ) |
2184 | 0 | aHScroll->Hide(); |
2185 | |
|
2186 | 0 | nControlAreaWidth = USHRT_MAX; |
2187 | |
|
2188 | 0 | tools::Long nOldRowSel = bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel; |
2189 | 0 | MultiSelection *pOldRowSel = bMultiSelection ? uRow.pSel : nullptr; |
2190 | |
|
2191 | 0 | pVScroll.disposeAndClear(); |
2192 | |
|
2193 | 0 | bMultiSelection = bool( nMode & BrowserMode::MULTISELECTION ); |
2194 | 0 | bColumnCursor = bool( nMode & BrowserMode::COLUMNSELECTION ); |
2195 | 0 | bKeepHighlight = bool( nMode & BrowserMode::KEEPHIGHLIGHT ); |
2196 | |
|
2197 | 0 | bHideSelect = ((nMode & BrowserMode::HIDESELECT) == BrowserMode::HIDESELECT); |
2198 | | // default: do not hide the cursor at all (untaken scrolling and such) |
2199 | 0 | bHideCursor = TRISTATE_FALSE; |
2200 | |
|
2201 | 0 | if ( BrowserMode::HIDECURSOR == ( nMode & BrowserMode::HIDECURSOR ) ) |
2202 | 0 | { |
2203 | 0 | bHideCursor = TRISTATE_TRUE; |
2204 | 0 | } |
2205 | |
|
2206 | 0 | m_bFocusOnlyCursor = ((nMode & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::NONE); |
2207 | |
|
2208 | 0 | bHLines = ( nMode & BrowserMode::HLINES ) == BrowserMode::HLINES; |
2209 | 0 | bVLines = ( nMode & BrowserMode::VLINES ) == BrowserMode::VLINES; |
2210 | |
|
2211 | 0 | pVScroll = VclPtr<ScrollAdaptor>::Create(this, false); |
2212 | 0 | pVScroll->SetLineSize( 1 ); |
2213 | 0 | pVScroll->SetPageSize(1); |
2214 | 0 | pVScroll->SetScrollHdl( LINK( this, BrowseBox, VertScrollHdl ) ); |
2215 | |
|
2216 | 0 | pDataWin->bAutoSizeLastCol = |
2217 | 0 | BrowserMode::AUTOSIZE_LASTCOL == ( nMode & BrowserMode::AUTOSIZE_LASTCOL ); |
2218 | | |
2219 | | // create a headerbar. what happens, if a headerbar has to be created and |
2220 | | // there already are columns? |
2221 | 0 | if ( BrowserMode::HEADERBAR_NEW == ( nMode & BrowserMode::HEADERBAR_NEW ) ) |
2222 | 0 | { |
2223 | 0 | if (!pDataWin->pHeaderBar) |
2224 | 0 | pDataWin->pHeaderBar = CreateHeaderBar( this ); |
2225 | 0 | } |
2226 | 0 | else |
2227 | 0 | { |
2228 | 0 | pDataWin->pHeaderBar.disposeAndClear(); |
2229 | 0 | } |
2230 | |
|
2231 | 0 | if ( bColumnCursor ) |
2232 | 0 | { |
2233 | 0 | if (!pColSel) |
2234 | 0 | pColSel.reset(new MultiSelection); |
2235 | 0 | pColSel->SetTotalRange( Range( 0, mvCols.size()-1 ) ); |
2236 | 0 | } |
2237 | 0 | else |
2238 | 0 | { |
2239 | 0 | pColSel.reset(); |
2240 | 0 | } |
2241 | |
|
2242 | 0 | if ( bMultiSelection ) |
2243 | 0 | { |
2244 | 0 | if ( pOldRowSel ) |
2245 | 0 | uRow.pSel = pOldRowSel; |
2246 | 0 | else |
2247 | 0 | uRow.pSel = new MultiSelection; |
2248 | 0 | } |
2249 | 0 | else |
2250 | 0 | { |
2251 | 0 | uRow.nSel = nOldRowSel; |
2252 | 0 | delete pOldRowSel; |
2253 | 0 | } |
2254 | |
|
2255 | 0 | if ( bBootstrapped ) |
2256 | 0 | { |
2257 | 0 | StateChanged( StateChangedType::InitShow ); |
2258 | 0 | if ( bMultiSelection && !pOldRowSel && |
2259 | 0 | nOldRowSel != BROWSER_ENDOFSELECTION ) |
2260 | 0 | uRow.pSel->Select( nOldRowSel ); |
2261 | 0 | } |
2262 | |
|
2263 | 0 | if ( pDataWin ) |
2264 | 0 | pDataWin->Invalidate(); |
2265 | | |
2266 | | // no cursor on handle column |
2267 | 0 | if ( nCurColId == HandleColumnId ) |
2268 | 0 | nCurColId = GetColumnId( 1 ); |
2269 | |
|
2270 | 0 | m_nCurrentMode = nMode; |
2271 | 0 | } |
2272 | | |
2273 | | |
2274 | | void BrowseBox::VisibleRowsChanged( sal_Int32, sal_uInt16 ) |
2275 | 0 | { |
2276 | | |
2277 | | // old behavior: automatically correct NumRows: |
2278 | 0 | if ( nRowCount < GetRowCount() ) |
2279 | 0 | { |
2280 | 0 | RowInserted(nRowCount,GetRowCount() - nRowCount, false); |
2281 | 0 | } |
2282 | 0 | else if ( nRowCount > GetRowCount() ) |
2283 | 0 | { |
2284 | 0 | RowRemoved(GetRowCount(), nRowCount - GetRowCount(), false); |
2285 | 0 | } |
2286 | 0 | } |
2287 | | |
2288 | | |
2289 | | bool BrowseBox::IsCursorMoveAllowed( sal_Int32, sal_uInt16 ) const |
2290 | | |
2291 | | /* [Description] |
2292 | | |
2293 | | This virtual method is always called before the cursor is moved directly. |
2294 | | By means of 'return false', we avoid doing this if e.g. a record |
2295 | | contradicts any rules. |
2296 | | |
2297 | | This method is not called, if the cursor movement results from removing or |
2298 | | deleting a row/column (thus, in cases where only a "cursor correction" happens). |
2299 | | |
2300 | | The base implementation currently always returns true. |
2301 | | */ |
2302 | | |
2303 | 0 | { |
2304 | 0 | return true; |
2305 | 0 | } |
2306 | | |
2307 | | |
2308 | | tools::Long BrowseBox::GetDataRowHeight() const |
2309 | 0 | { |
2310 | 0 | return CalcZoom(m_nDataRowHeight ? m_nDataRowHeight : ImpGetDataRowHeight()); |
2311 | 0 | } |
2312 | | |
2313 | | |
2314 | | VclPtr<BrowserHeader> BrowseBox::CreateHeaderBar( BrowseBox* pParent ) |
2315 | 0 | { |
2316 | 0 | VclPtr<BrowserHeader> pNewBar = VclPtr<BrowserHeader>::Create( pParent ); |
2317 | 0 | pNewBar->SetStartDragHdl( LINK( this, BrowseBox, StartDragHdl ) ); |
2318 | 0 | return pNewBar; |
2319 | 0 | } |
2320 | | |
2321 | | void BrowseBox::SetHeaderBar( BrowserHeader* pHeaderBar ) |
2322 | 0 | { |
2323 | 0 | pDataWin->pHeaderBar.disposeAndClear(); |
2324 | 0 | pDataWin->pHeaderBar = pHeaderBar; |
2325 | 0 | pDataWin->pHeaderBar->SetStartDragHdl( LINK( this, BrowseBox, StartDragHdl ) ); |
2326 | 0 | } |
2327 | | |
2328 | | tools::Long BrowseBox::GetTitleHeight() const |
2329 | 0 | { |
2330 | 0 | tools::Long nHeight; |
2331 | | // ask the header bar for the text height (if possible), as the header bar's font is adjusted with |
2332 | | // our (and the header's) zoom factor |
2333 | 0 | HeaderBar* pHeaderBar = pDataWin->pHeaderBar; |
2334 | 0 | if ( pHeaderBar ) |
2335 | 0 | nHeight = pHeaderBar->GetTextHeight(); |
2336 | 0 | else |
2337 | 0 | nHeight = GetTextHeight(); |
2338 | |
|
2339 | 0 | return nTitleLines ? nTitleLines * nHeight + 4 : 0; |
2340 | 0 | } |
2341 | | |
2342 | | tools::Long BrowseBox::CalcReverseZoom(tools::Long nVal) const |
2343 | 0 | { |
2344 | 0 | if (IsZoom()) |
2345 | 0 | { |
2346 | 0 | const Fraction& rZoom = GetZoom(); |
2347 | 0 | double n = static_cast<double>(nVal); |
2348 | 0 | n *= static_cast<double>(rZoom.GetDenominator()); |
2349 | 0 | if (!rZoom.GetNumerator()) |
2350 | 0 | throw o3tl::divide_by_zero(); |
2351 | 0 | n /= static_cast<double>(rZoom.GetNumerator()); |
2352 | 0 | nVal = n>0 ? static_cast<tools::Long>(n + 0.5) : -static_cast<tools::Long>(-n + 0.5); |
2353 | 0 | } |
2354 | | |
2355 | 0 | return nVal; |
2356 | 0 | } |
2357 | | |
2358 | | void BrowseBox::CursorMoved() |
2359 | 0 | { |
2360 | | // before implementing more here, please adjust the EditBrowseBox |
2361 | |
|
2362 | 0 | if ( isAccessibleAlive() && HasFocus() ) |
2363 | 0 | commitTableEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, |
2364 | 0 | Any(css::uno::Reference<css::accessibility::XAccessible>( |
2365 | 0 | CreateAccessibleCell(GetCurRow(), GetColumnPos(GetCurColumnId())))), |
2366 | 0 | Any()); |
2367 | 0 | } |
2368 | | |
2369 | | void BrowseBox::LoseFocus() |
2370 | 0 | { |
2371 | 0 | SAL_INFO("svtools", "BrowseBox::LoseFocus " << this ); |
2372 | | |
2373 | 0 | if ( bHasFocus ) |
2374 | 0 | { |
2375 | 0 | SAL_INFO("svtools", "BrowseBox::HideCursor " << this ); |
2376 | 0 | DoHideCursor(); |
2377 | |
|
2378 | 0 | if ( !bKeepHighlight ) |
2379 | 0 | { |
2380 | 0 | ToggleSelection(); |
2381 | 0 | bSelectionIsVisible = false; |
2382 | 0 | } |
2383 | |
|
2384 | 0 | bHasFocus = false; |
2385 | 0 | } |
2386 | 0 | Control::LoseFocus(); |
2387 | 0 | } |
2388 | | |
2389 | | |
2390 | | void BrowseBox::GetFocus() |
2391 | 0 | { |
2392 | 0 | SAL_INFO("svtools", "BrowseBox::GetFocus " << this ); |
2393 | | |
2394 | 0 | if ( !bHasFocus ) |
2395 | 0 | { |
2396 | 0 | if ( !bSelectionIsVisible ) |
2397 | 0 | { |
2398 | 0 | bSelectionIsVisible = true; |
2399 | 0 | if ( bBootstrapped ) |
2400 | 0 | ToggleSelection(); |
2401 | 0 | } |
2402 | |
|
2403 | 0 | bHasFocus = true; |
2404 | 0 | DoShowCursor(); |
2405 | 0 | } |
2406 | 0 | Control::GetFocus(); |
2407 | 0 | } |
2408 | | |
2409 | | |
2410 | | sal_uInt16 BrowseBox::GetVisibleRows() const |
2411 | 0 | { |
2412 | 0 | return static_cast<sal_uInt16>((pDataWin->GetOutputSizePixel().Height() - 1 )/ GetDataRowHeight() + 1); |
2413 | 0 | } |
2414 | | |
2415 | | BrowserDataWin& BrowseBox::GetDataWindow() const |
2416 | 0 | { |
2417 | 0 | return *pDataWin; |
2418 | 0 | } |
2419 | | |
2420 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |