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