1 | /* $Id: UIChooserItemGroup.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBox Qt GUI - UIChooserItemGroup class implementation.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2012-2024 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
26 | */
|
---|
27 |
|
---|
28 | /* Qt includes: */
|
---|
29 | #include <QApplication>
|
---|
30 | #include <QGraphicsLinearLayout>
|
---|
31 | #include <QGraphicsScene>
|
---|
32 | #include <QGraphicsSceneDragDropEvent>
|
---|
33 | #include <QGraphicsView>
|
---|
34 | #include <QHBoxLayout>
|
---|
35 | #include <QLineEdit>
|
---|
36 | #include <QPainter>
|
---|
37 | #include <QRegularExpression>
|
---|
38 | #include <QStyleOptionGraphicsItem>
|
---|
39 | #include <QWindow>
|
---|
40 |
|
---|
41 | /* GUI includes: */
|
---|
42 | #include "UIChooserItemGlobal.h"
|
---|
43 | #include "UIChooserItemGroup.h"
|
---|
44 | #include "UIChooserItemMachine.h"
|
---|
45 | #include "UIChooserModel.h"
|
---|
46 | #include "UIChooserNodeGroup.h"
|
---|
47 | #include "UIChooserNodeMachine.h"
|
---|
48 | #include "UIGraphicsRotatorButton.h"
|
---|
49 | #include "UIGraphicsScrollArea.h"
|
---|
50 | #include "UIIconPool.h"
|
---|
51 | #include "UIImageTools.h"
|
---|
52 | #include "UITranslationEventListener.h"
|
---|
53 | #include "UIVirtualBoxManager.h"
|
---|
54 | #include "UIVirtualMachineItem.h"
|
---|
55 |
|
---|
56 |
|
---|
57 | /*********************************************************************************************************************************
|
---|
58 | * Class UIChooserItemGroup implementation. *
|
---|
59 | *********************************************************************************************************************************/
|
---|
60 |
|
---|
61 | UIChooserItemGroup::UIChooserItemGroup(QGraphicsScene *pScene, UIChooserNodeGroup *pNode)
|
---|
62 | : UIChooserItem(0, pNode)
|
---|
63 | , m_pScene(pScene)
|
---|
64 | , m_iRootBackgroundDarknessStart(0)
|
---|
65 | , m_iRootBackgroundDarknessFinal(0)
|
---|
66 | , m_iItemBackgroundDarknessStart(0)
|
---|
67 | , m_iItemBackgroundDarknessFinal(0)
|
---|
68 | , m_iHighlightLightness(0)
|
---|
69 | , m_iAdditionalHeight(0)
|
---|
70 | , m_pToggleButton(0)
|
---|
71 | , m_pNameEditorWidget(0)
|
---|
72 | , m_pContainerFavorite(0)
|
---|
73 | , m_pLayoutFavorite(0)
|
---|
74 | , m_pScrollArea(0)
|
---|
75 | , m_pContainer(0)
|
---|
76 | , m_pLayout(0)
|
---|
77 | , m_pLayoutGlobal(0)
|
---|
78 | , m_pLayoutGroup(0)
|
---|
79 | , m_pLayoutMachine(0)
|
---|
80 | , m_iPreviousMinimumWidthHint(0)
|
---|
81 | {
|
---|
82 | prepare();
|
---|
83 | }
|
---|
84 |
|
---|
85 | UIChooserItemGroup::UIChooserItemGroup(UIChooserItem *pParent, UIChooserNodeGroup *pNode)
|
---|
86 | : UIChooserItem(pParent, pNode)
|
---|
87 | , m_pScene(0)
|
---|
88 | , m_iRootBackgroundDarknessStart(0)
|
---|
89 | , m_iRootBackgroundDarknessFinal(0)
|
---|
90 | , m_iItemBackgroundDarknessStart(0)
|
---|
91 | , m_iItemBackgroundDarknessFinal(0)
|
---|
92 | , m_iHighlightLightness(0)
|
---|
93 | , m_iAdditionalHeight(0)
|
---|
94 | , m_pToggleButton(0)
|
---|
95 | , m_pNameEditorWidget(0)
|
---|
96 | , m_pContainerFavorite(0)
|
---|
97 | , m_pLayoutFavorite(0)
|
---|
98 | , m_pScrollArea(0)
|
---|
99 | , m_pContainer(0)
|
---|
100 | , m_pLayout(0)
|
---|
101 | , m_pLayoutGlobal(0)
|
---|
102 | , m_pLayoutGroup(0)
|
---|
103 | , m_pLayoutMachine(0)
|
---|
104 | , m_iPreviousMinimumWidthHint(0)
|
---|
105 | {
|
---|
106 | prepare();
|
---|
107 | }
|
---|
108 |
|
---|
109 | UIChooserItemGroup::~UIChooserItemGroup()
|
---|
110 | {
|
---|
111 | cleanup();
|
---|
112 | }
|
---|
113 |
|
---|
114 | UIChooserNodeGroup *UIChooserItemGroup::nodeToGroupType() const
|
---|
115 | {
|
---|
116 | return node() ? node()->toGroupNode() : 0;
|
---|
117 | }
|
---|
118 |
|
---|
119 | QUuid UIChooserItemGroup::id() const
|
---|
120 | {
|
---|
121 | return nodeToGroupType() ? nodeToGroupType()->id() : QUuid();
|
---|
122 | }
|
---|
123 |
|
---|
124 | UIChooserNodeGroupType UIChooserItemGroup::groupType() const
|
---|
125 | {
|
---|
126 | return nodeToGroupType() ? nodeToGroupType()->groupType() : UIChooserNodeGroupType_Invalid;
|
---|
127 | }
|
---|
128 |
|
---|
129 | bool UIChooserItemGroup::isClosed() const
|
---|
130 | {
|
---|
131 | return nodeToGroupType()->isClosed() && !isRoot();
|
---|
132 | }
|
---|
133 |
|
---|
134 | void UIChooserItemGroup::close(bool fAnimated /* = true */)
|
---|
135 | {
|
---|
136 | AssertMsg(!isRoot(), ("Can't close root-item!"));
|
---|
137 | m_pToggleButton->setToggled(false, fAnimated);
|
---|
138 | }
|
---|
139 |
|
---|
140 | bool UIChooserItemGroup::isOpened() const
|
---|
141 | {
|
---|
142 | return nodeToGroupType()->isOpened() || isRoot();
|
---|
143 | }
|
---|
144 |
|
---|
145 | void UIChooserItemGroup::open(bool fAnimated /* = true */)
|
---|
146 | {
|
---|
147 | AssertMsg(!isRoot(), ("Can't open root-item!"));
|
---|
148 | m_pToggleButton->setToggled(true, fAnimated);
|
---|
149 | }
|
---|
150 |
|
---|
151 | void UIChooserItemGroup::updateFavorites()
|
---|
152 | {
|
---|
153 | /* Global items only for now, move items to corresponding layout: */
|
---|
154 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Global))
|
---|
155 | if (pItem->isFavorite())
|
---|
156 | {
|
---|
157 | for (int iIndex = 0; iIndex < m_pLayoutGlobal->count(); ++iIndex)
|
---|
158 | if (m_pLayoutGlobal->itemAt(iIndex) == pItem)
|
---|
159 | m_pLayoutFavorite->addItem(pItem);
|
---|
160 | }
|
---|
161 | else
|
---|
162 | {
|
---|
163 | for (int iIndex = 0; iIndex < m_pLayoutFavorite->count(); ++iIndex)
|
---|
164 | if (m_pLayoutFavorite->itemAt(iIndex) == pItem)
|
---|
165 | m_pLayoutGlobal->addItem(pItem);
|
---|
166 | }
|
---|
167 |
|
---|
168 | /* Update/activate children layout: */
|
---|
169 | m_pLayout->updateGeometry();
|
---|
170 | m_pLayout->activate();
|
---|
171 |
|
---|
172 | /* Relayout model: */
|
---|
173 | model()->updateLayout();
|
---|
174 | }
|
---|
175 |
|
---|
176 | int UIChooserItemGroup::scrollingValue() const
|
---|
177 | {
|
---|
178 | return m_pScrollArea->scrollingValue();
|
---|
179 | }
|
---|
180 |
|
---|
181 | void UIChooserItemGroup::setScrollingValue(int iValue)
|
---|
182 | {
|
---|
183 | m_pScrollArea->setScrollingValue(iValue);
|
---|
184 | }
|
---|
185 |
|
---|
186 | void UIChooserItemGroup::scrollBy(int iDelta)
|
---|
187 | {
|
---|
188 | m_pScrollArea->scrollBy(iDelta);
|
---|
189 | }
|
---|
190 |
|
---|
191 | void UIChooserItemGroup::makeSureItemIsVisible(UIChooserItem *pItem)
|
---|
192 | {
|
---|
193 | /* Make sure item exists: */
|
---|
194 | AssertPtrReturnVoid(pItem);
|
---|
195 |
|
---|
196 | /* Convert child rectangle to local coordinates for this group. This also
|
---|
197 | * works for a child at any sub-level, doesn't necessary of this group. */
|
---|
198 | const QPointF positionInScene = pItem->mapToScene(QPointF(0, 0));
|
---|
199 | const QPointF positionInGroup = mapFromScene(positionInScene);
|
---|
200 | const QRectF itemRectInGroup = QRectF(positionInGroup, pItem->size());
|
---|
201 | m_pScrollArea->makeSureRectIsVisible(itemRectInGroup);
|
---|
202 | }
|
---|
203 |
|
---|
204 | /* static */
|
---|
205 | QString UIChooserItemGroup::className()
|
---|
206 | {
|
---|
207 | return "UIChooserItemGroup";
|
---|
208 | }
|
---|
209 |
|
---|
210 | void UIChooserItemGroup::sltRetranslateUI()
|
---|
211 | {
|
---|
212 | updateToggleButtonToolTip();
|
---|
213 | }
|
---|
214 |
|
---|
215 | void UIChooserItemGroup::showEvent(QShowEvent *pEvent)
|
---|
216 | {
|
---|
217 | /* Call to base-class: */
|
---|
218 | UIChooserItem::showEvent(pEvent);
|
---|
219 |
|
---|
220 | /* Update pixmaps: */
|
---|
221 | updatePixmaps();
|
---|
222 | }
|
---|
223 |
|
---|
224 | void UIChooserItemGroup::resizeEvent(QGraphicsSceneResizeEvent *pEvent)
|
---|
225 | {
|
---|
226 | /* Call to base-class: */
|
---|
227 | UIChooserItem::resizeEvent(pEvent);
|
---|
228 |
|
---|
229 | /* What is the new geometry? */
|
---|
230 | const QRectF newGeometry = geometry();
|
---|
231 |
|
---|
232 | /* Should we update visible name? */
|
---|
233 | if (previousGeometry().width() != newGeometry.width())
|
---|
234 | updateVisibleName();
|
---|
235 |
|
---|
236 | /* Remember the new geometry: */
|
---|
237 | setPreviousGeometry(newGeometry);
|
---|
238 | }
|
---|
239 |
|
---|
240 | void UIChooserItemGroup::hoverMoveEvent(QGraphicsSceneHoverEvent *pEvent)
|
---|
241 | {
|
---|
242 | /* Skip if hovered: */
|
---|
243 | if (isHovered())
|
---|
244 | return;
|
---|
245 |
|
---|
246 | /* Prepare variables: */
|
---|
247 | const QPoint pos = pEvent->pos().toPoint();
|
---|
248 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
249 | const int iHeaderHeight = m_minimumHeaderSize.height();
|
---|
250 | const int iFullHeaderHeight = 2 * iMarginV + iHeaderHeight;
|
---|
251 | /* Skip if hovered part out of the header: */
|
---|
252 | if (pos.y() >= iFullHeaderHeight)
|
---|
253 | return;
|
---|
254 |
|
---|
255 | /* Call to base-class: */
|
---|
256 | UIChooserItem::hoverMoveEvent(pEvent);
|
---|
257 |
|
---|
258 | /* Update linked values: */
|
---|
259 | updateVisibleName();
|
---|
260 | }
|
---|
261 |
|
---|
262 | void UIChooserItemGroup::hoverLeaveEvent(QGraphicsSceneHoverEvent *pEvent)
|
---|
263 | {
|
---|
264 | /* Skip if not hovered: */
|
---|
265 | if (!isHovered())
|
---|
266 | return;
|
---|
267 |
|
---|
268 | /* Call to base-class: */
|
---|
269 | UIChooserItem::hoverLeaveEvent(pEvent);
|
---|
270 |
|
---|
271 | /* Update linked values: */
|
---|
272 | updateVisibleName();
|
---|
273 | }
|
---|
274 |
|
---|
275 | void UIChooserItemGroup::paint(QPainter *pPainter, const QStyleOptionGraphicsItem *pOptions, QWidget* /* pWidget = 0 */)
|
---|
276 | {
|
---|
277 | /* Acquire rectangle: */
|
---|
278 | const QRect rectangle = pOptions->rect;
|
---|
279 |
|
---|
280 | /* Paint background: */
|
---|
281 | paintBackground(pPainter, rectangle);
|
---|
282 | /* Paint frame: */
|
---|
283 | paintFrame(pPainter, rectangle);
|
---|
284 | /* Paint header: */
|
---|
285 | paintHeader(pPainter, rectangle);
|
---|
286 | }
|
---|
287 |
|
---|
288 | void UIChooserItemGroup::startEditing()
|
---|
289 | {
|
---|
290 | /* Not for root: */
|
---|
291 | if (isRoot())
|
---|
292 | return;
|
---|
293 |
|
---|
294 | /* Not while saving groups: */
|
---|
295 | if (model()->isGroupSavingInProgress())
|
---|
296 | return;
|
---|
297 |
|
---|
298 | /* Make sure item visible: */
|
---|
299 | if (model()->root())
|
---|
300 | model()->root()->toGroupItem() ->makeSureItemIsVisible(this);
|
---|
301 |
|
---|
302 | /* Assign name-editor text: */
|
---|
303 | m_pNameEditorWidget->setText(name());
|
---|
304 |
|
---|
305 | /* Layout name-editor: */
|
---|
306 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
307 | const int iHeaderHeight = 2 * iMarginV + m_minimumHeaderSize.height();
|
---|
308 | const QSize headerSize = QSize(geometry().width(), iHeaderHeight);
|
---|
309 | const QGraphicsView *pView = model()->scene()->views().first();
|
---|
310 | const QPointF viewPoint = pView->mapFromScene(mapToScene(QPointF(0, 0)));
|
---|
311 | const QPoint globalPoint = pView->parentWidget()->mapToGlobal(viewPoint.toPoint());
|
---|
312 | m_pNameEditorWidget->move(globalPoint);
|
---|
313 | m_pNameEditorWidget->resize(headerSize);
|
---|
314 |
|
---|
315 | /* Show name-editor: */
|
---|
316 | m_pNameEditorWidget->show();
|
---|
317 | m_pNameEditorWidget->setFocus();
|
---|
318 | }
|
---|
319 |
|
---|
320 | void UIChooserItemGroup::updateItem()
|
---|
321 | {
|
---|
322 | /* Update this group-item: */
|
---|
323 | updateVisibleName();
|
---|
324 | updateMinimumHeaderSize();
|
---|
325 | updateToolTip();
|
---|
326 | update();
|
---|
327 |
|
---|
328 | /* Update parent group-item: */
|
---|
329 | if (parentItem())
|
---|
330 | {
|
---|
331 | parentItem()->updateToolTip();
|
---|
332 | parentItem()->update();
|
---|
333 | }
|
---|
334 | }
|
---|
335 |
|
---|
336 | void UIChooserItemGroup::updateToolTip()
|
---|
337 | {
|
---|
338 | /* Not for root item: */
|
---|
339 | if (isRoot())
|
---|
340 | return;
|
---|
341 |
|
---|
342 | /* Prepare variables: */
|
---|
343 | QStringList toolTipInfo;
|
---|
344 |
|
---|
345 | /* Should we add name? */
|
---|
346 | if (!name().isEmpty())
|
---|
347 | {
|
---|
348 | /* Template: */
|
---|
349 | QString strTemplateForName = tr("<b>%1</b>", "Group item tool-tip / Group name");
|
---|
350 |
|
---|
351 | /* Append value: */
|
---|
352 | toolTipInfo << strTemplateForName.arg(name());
|
---|
353 | }
|
---|
354 |
|
---|
355 | /* Should we add group info? */
|
---|
356 | if (!items(UIChooserNodeType_Group).isEmpty())
|
---|
357 | {
|
---|
358 | /* Template: */
|
---|
359 | QString strGroupCount = tr("%n group(s)", "Group item tool-tip / Group info", items(UIChooserNodeType_Group).size());
|
---|
360 |
|
---|
361 | /* Append value: */
|
---|
362 | QString strValue = tr("<nobr>%1</nobr>", "Group item tool-tip / Group info wrapper").arg(strGroupCount);
|
---|
363 | toolTipInfo << strValue;
|
---|
364 | }
|
---|
365 |
|
---|
366 | /* Should we add machine info? */
|
---|
367 | if (!items(UIChooserNodeType_Machine).isEmpty())
|
---|
368 | {
|
---|
369 | /* Check if 'this' group contains started VMs: */
|
---|
370 | int iCountOfStartedMachineItems = 0;
|
---|
371 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Machine))
|
---|
372 | {
|
---|
373 | AssertPtrReturnVoid(pItem);
|
---|
374 | UIChooserItemMachine *pMachineItem = pItem->toMachineItem();
|
---|
375 | AssertPtrReturnVoid(pMachineItem);
|
---|
376 | AssertPtrReturnVoid(pMachineItem->cache());
|
---|
377 | if (pMachineItem->cache()->isItemStarted())
|
---|
378 | ++iCountOfStartedMachineItems;
|
---|
379 | }
|
---|
380 | /* Template: */
|
---|
381 | QString strMachineCount = tr("%n machine(s)", "Group item tool-tip / Machine info", items(UIChooserNodeType_Machine).size());
|
---|
382 | QString strStartedMachineCount = tr("(%n running)", "Group item tool-tip / Running machine info", iCountOfStartedMachineItems);
|
---|
383 |
|
---|
384 | /* Append value: */
|
---|
385 | QString strValue = !iCountOfStartedMachineItems ?
|
---|
386 | tr("<nobr>%1</nobr>", "Group item tool-tip / Machine info wrapper").arg(strMachineCount) :
|
---|
387 | tr("<nobr>%1 %2</nobr>", "Group item tool-tip / Machine info wrapper, including running").arg(strMachineCount).arg(strStartedMachineCount);
|
---|
388 | toolTipInfo << strValue;
|
---|
389 | }
|
---|
390 |
|
---|
391 | /* Set tool-tip: */
|
---|
392 | setToolTip(toolTipInfo.join("<br>"));
|
---|
393 | }
|
---|
394 |
|
---|
395 | void UIChooserItemGroup::installEventFilterHelper(QObject *pSource)
|
---|
396 | {
|
---|
397 | /* The only object which need's that filter for now is scroll-area: */
|
---|
398 | pSource->installEventFilter(m_pScrollArea);
|
---|
399 | }
|
---|
400 |
|
---|
401 | QList<UIChooserItem*> UIChooserItemGroup::items(UIChooserNodeType type /* = UIChooserNodeType_Any */) const
|
---|
402 | {
|
---|
403 | switch (type)
|
---|
404 | {
|
---|
405 | case UIChooserNodeType_Any: return items(UIChooserNodeType_Global) + items(UIChooserNodeType_Group) + items(UIChooserNodeType_Machine);
|
---|
406 | case UIChooserNodeType_Global: return m_globalItems;
|
---|
407 | case UIChooserNodeType_Group: return m_groupItems;
|
---|
408 | case UIChooserNodeType_Machine: return m_machineItems;
|
---|
409 | default: break;
|
---|
410 | }
|
---|
411 | return QList<UIChooserItem*>();
|
---|
412 | }
|
---|
413 |
|
---|
414 | void UIChooserItemGroup::addItem(UIChooserItem *pItem, bool fFavorite, int iPosition)
|
---|
415 | {
|
---|
416 | /* Check item type: */
|
---|
417 | switch (pItem->type())
|
---|
418 | {
|
---|
419 | case UIChooserNodeType_Global:
|
---|
420 | {
|
---|
421 | AssertMsg(!m_globalItems.contains(pItem), ("Global-item already added!"));
|
---|
422 | if (iPosition < 0 || iPosition >= m_globalItems.size())
|
---|
423 | {
|
---|
424 | if (fFavorite)
|
---|
425 | m_pLayoutFavorite->addItem(pItem);
|
---|
426 | else
|
---|
427 | m_pLayoutGlobal->addItem(pItem);
|
---|
428 | m_globalItems.append(pItem);
|
---|
429 | }
|
---|
430 | else
|
---|
431 | {
|
---|
432 | if (fFavorite)
|
---|
433 | m_pLayoutFavorite->insertItem(iPosition, pItem);
|
---|
434 | else
|
---|
435 | m_pLayoutGlobal->insertItem(iPosition, pItem);
|
---|
436 | m_globalItems.insert(iPosition, pItem);
|
---|
437 | }
|
---|
438 | break;
|
---|
439 | }
|
---|
440 | case UIChooserNodeType_Group:
|
---|
441 | {
|
---|
442 | AssertMsg(!m_groupItems.contains(pItem), ("Group-item already added!"));
|
---|
443 | if (iPosition < 0 || iPosition >= m_groupItems.size())
|
---|
444 | {
|
---|
445 | m_pLayoutGroup->addItem(pItem);
|
---|
446 | m_groupItems.append(pItem);
|
---|
447 | }
|
---|
448 | else
|
---|
449 | {
|
---|
450 | m_pLayoutGroup->insertItem(iPosition, pItem);
|
---|
451 | m_groupItems.insert(iPosition, pItem);
|
---|
452 | }
|
---|
453 | break;
|
---|
454 | }
|
---|
455 | case UIChooserNodeType_Machine:
|
---|
456 | {
|
---|
457 | AssertMsg(!m_machineItems.contains(pItem), ("Machine-item already added!"));
|
---|
458 | if (iPosition < 0 || iPosition >= m_machineItems.size())
|
---|
459 | {
|
---|
460 | m_pLayoutMachine->addItem(pItem);
|
---|
461 | m_machineItems.append(pItem);
|
---|
462 | }
|
---|
463 | else
|
---|
464 | {
|
---|
465 | m_pLayoutMachine->insertItem(iPosition, pItem);
|
---|
466 | m_machineItems.insert(iPosition, pItem);
|
---|
467 | }
|
---|
468 | break;
|
---|
469 | }
|
---|
470 | default:
|
---|
471 | {
|
---|
472 | AssertMsgFailed(("Invalid item type!"));
|
---|
473 | break;
|
---|
474 | }
|
---|
475 | }
|
---|
476 |
|
---|
477 | /* Update linked values: */
|
---|
478 | updateLayoutSpacings();
|
---|
479 | updateItemCountInfo();
|
---|
480 | updateToolTip();
|
---|
481 | updateGeometry();
|
---|
482 | }
|
---|
483 |
|
---|
484 | void UIChooserItemGroup::removeItem(UIChooserItem *pItem)
|
---|
485 | {
|
---|
486 | /* Check item type: */
|
---|
487 | switch (pItem->type())
|
---|
488 | {
|
---|
489 | case UIChooserNodeType_Global:
|
---|
490 | {
|
---|
491 | AssertMsg(m_globalItems.contains(pItem), ("Global-item was not found!"));
|
---|
492 | m_globalItems.removeAt(m_globalItems.indexOf(pItem));
|
---|
493 | if (pItem->isFavorite())
|
---|
494 | m_pLayoutFavorite->removeItem(pItem);
|
---|
495 | else
|
---|
496 | m_pLayoutGlobal->removeItem(pItem);
|
---|
497 | break;
|
---|
498 | }
|
---|
499 | case UIChooserNodeType_Group:
|
---|
500 | {
|
---|
501 | AssertMsg(m_groupItems.contains(pItem), ("Group-item was not found!"));
|
---|
502 | m_groupItems.removeAt(m_groupItems.indexOf(pItem));
|
---|
503 | if (pItem->isFavorite())
|
---|
504 | m_pLayoutFavorite->removeItem(pItem);
|
---|
505 | else
|
---|
506 | m_pLayoutGroup->removeItem(pItem);
|
---|
507 | break;
|
---|
508 | }
|
---|
509 | case UIChooserNodeType_Machine:
|
---|
510 | {
|
---|
511 | AssertMsg(m_machineItems.contains(pItem), ("Machine-item was not found!"));
|
---|
512 | m_machineItems.removeAt(m_machineItems.indexOf(pItem));
|
---|
513 | if (pItem->isFavorite())
|
---|
514 | m_pLayoutFavorite->removeItem(pItem);
|
---|
515 | else
|
---|
516 | m_pLayoutMachine->removeItem(pItem);
|
---|
517 | break;
|
---|
518 | }
|
---|
519 | default:
|
---|
520 | {
|
---|
521 | AssertMsgFailed(("Invalid item type!"));
|
---|
522 | break;
|
---|
523 | }
|
---|
524 | }
|
---|
525 |
|
---|
526 | /* Update linked values: */
|
---|
527 | updateLayoutSpacings();
|
---|
528 | updateItemCountInfo();
|
---|
529 | updateToolTip();
|
---|
530 | updateGeometry();
|
---|
531 | }
|
---|
532 |
|
---|
533 | UIChooserItem* UIChooserItemGroup::searchForItem(const QString &strSearchTag, int iSearchFlags)
|
---|
534 | {
|
---|
535 | /* Are we searching among group-items? */
|
---|
536 | if ( ( iSearchFlags & UIChooserItemSearchFlag_LocalGroup
|
---|
537 | && groupType() == UIChooserNodeGroupType_Local)
|
---|
538 | || ( iSearchFlags & UIChooserItemSearchFlag_CloudProvider
|
---|
539 | && groupType() == UIChooserNodeGroupType_Provider)
|
---|
540 | || ( iSearchFlags & UIChooserItemSearchFlag_CloudProfile
|
---|
541 | && groupType() == UIChooserNodeGroupType_Profile))
|
---|
542 | {
|
---|
543 | /* Are we searching by the exact ID? */
|
---|
544 | if (iSearchFlags & UIChooserItemSearchFlag_ExactId)
|
---|
545 | {
|
---|
546 | /* Exact ID matches? */
|
---|
547 | if (id().toString() == strSearchTag)
|
---|
548 | return this;
|
---|
549 | }
|
---|
550 | /* Are we searching by the exact name? */
|
---|
551 | else if (iSearchFlags & UIChooserItemSearchFlag_ExactName)
|
---|
552 | {
|
---|
553 | /* Exact name matches? */
|
---|
554 | if (name() == strSearchTag)
|
---|
555 | return this;
|
---|
556 | }
|
---|
557 | /* Are we searching by the full name? */
|
---|
558 | else if (iSearchFlags & UIChooserItemSearchFlag_FullName)
|
---|
559 | {
|
---|
560 | /* Full name matches? */
|
---|
561 | if (fullName() == strSearchTag)
|
---|
562 | return this;
|
---|
563 | }
|
---|
564 | /* Are we searching by the few first symbols? */
|
---|
565 | else
|
---|
566 | {
|
---|
567 | /* Name starts with passed symbols? */
|
---|
568 | if (name().startsWith(strSearchTag, Qt::CaseInsensitive))
|
---|
569 | return this;
|
---|
570 | }
|
---|
571 | }
|
---|
572 |
|
---|
573 | /* Search among all the children, but machines first: */
|
---|
574 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Machine))
|
---|
575 | if (UIChooserItem *pFoundItem = pItem->searchForItem(strSearchTag, iSearchFlags))
|
---|
576 | return pFoundItem;
|
---|
577 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Global))
|
---|
578 | if (UIChooserItem *pFoundItem = pItem->searchForItem(strSearchTag, iSearchFlags))
|
---|
579 | return pFoundItem;
|
---|
580 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Group))
|
---|
581 | if (UIChooserItem *pFoundItem = pItem->searchForItem(strSearchTag, iSearchFlags))
|
---|
582 | return pFoundItem;
|
---|
583 |
|
---|
584 | /* Found nothing? */
|
---|
585 | return 0;
|
---|
586 | }
|
---|
587 |
|
---|
588 | UIChooserItem *UIChooserItemGroup::firstMachineItem()
|
---|
589 | {
|
---|
590 | /* If this group-item have at least one machine-item: */
|
---|
591 | if (node()->hasNodes(UIChooserNodeType_Machine))
|
---|
592 | /* Return the first machine-item: */
|
---|
593 | return items(UIChooserNodeType_Machine).first()->firstMachineItem();
|
---|
594 | /* If this group-item have at least one group-item: */
|
---|
595 | else if (node()->hasNodes(UIChooserNodeType_Group))
|
---|
596 | /* Return the first machine-item of the first group-item: */
|
---|
597 | return items(UIChooserNodeType_Group).first()->firstMachineItem();
|
---|
598 | /* Found nothing? */
|
---|
599 | return 0;
|
---|
600 | }
|
---|
601 |
|
---|
602 | void UIChooserItemGroup::updateGeometry()
|
---|
603 | {
|
---|
604 | /* Update/activate children layout: */
|
---|
605 | m_pLayout->updateGeometry();
|
---|
606 | m_pLayout->activate();
|
---|
607 |
|
---|
608 | /* Call to base-class: */
|
---|
609 | UIChooserItem::updateGeometry();
|
---|
610 |
|
---|
611 | /* Special handling for root-groups: */
|
---|
612 | if (isRoot())
|
---|
613 | {
|
---|
614 | /* Root-group should notify Chooser-view if minimum-width-hint was changed: */
|
---|
615 | const int iMinimumWidthHint = minimumWidthHint();
|
---|
616 | if (m_iPreviousMinimumWidthHint != iMinimumWidthHint)
|
---|
617 | {
|
---|
618 | /* Save new minimum-width-hint, notify listener: */
|
---|
619 | m_iPreviousMinimumWidthHint = iMinimumWidthHint;
|
---|
620 | emit sigMinimumWidthHintChanged(m_iPreviousMinimumWidthHint);
|
---|
621 | }
|
---|
622 | }
|
---|
623 | }
|
---|
624 |
|
---|
625 | void UIChooserItemGroup::updateLayout()
|
---|
626 | {
|
---|
627 | /* Prepare variables: */
|
---|
628 | const int iMarginHL = data(GroupItemData_MarginHL).toInt();
|
---|
629 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
630 | const int iParentIndent = data(GroupItemData_ParentIndent).toInt();
|
---|
631 | const int iFullHeaderHeight = m_minimumHeaderSize.height();
|
---|
632 | int iPreviousVerticalIndent = 0;
|
---|
633 |
|
---|
634 | /* Header (root-item): */
|
---|
635 | if (isRoot())
|
---|
636 | {
|
---|
637 | /* Acquire view: */
|
---|
638 | const QGraphicsView *pView = model()->scene()->views().first();
|
---|
639 |
|
---|
640 | /* Adjust scroll-view geometry: */
|
---|
641 | QSize viewSize = pView->size();
|
---|
642 | viewSize.setHeight(viewSize.height() - iPreviousVerticalIndent);
|
---|
643 | /* Adjust favorite children container: */
|
---|
644 | m_pContainerFavorite->resize(viewSize.width(), m_pContainerFavorite->minimumSizeHint().height());
|
---|
645 | m_pContainerFavorite->setPos(0, iPreviousVerticalIndent);
|
---|
646 | iPreviousVerticalIndent += m_pContainerFavorite->minimumSizeHint().height();
|
---|
647 | /* Adjust other children scroll-area: */
|
---|
648 | m_pScrollArea->resize(viewSize.width(), viewSize.height() - m_pContainerFavorite->minimumSizeHint().height());
|
---|
649 | m_pScrollArea->setPos(0, iPreviousVerticalIndent);
|
---|
650 | }
|
---|
651 | /* Header (non-root-item): */
|
---|
652 | else
|
---|
653 | {
|
---|
654 | /* Toggle-button: */
|
---|
655 | if (m_pToggleButton)
|
---|
656 | {
|
---|
657 | /* Prepare variables: */
|
---|
658 | int iToggleButtonHeight = m_toggleButtonSize.height();
|
---|
659 | /* Layout toggle-button: */
|
---|
660 | int iToggleButtonX = iMarginHL;
|
---|
661 | int iToggleButtonY = iToggleButtonHeight == iFullHeaderHeight ? iMarginV :
|
---|
662 | iMarginV + (iFullHeaderHeight - iToggleButtonHeight) / 2;
|
---|
663 | m_pToggleButton->setPos(iToggleButtonX, iToggleButtonY);
|
---|
664 | /* Show toggle-button: */
|
---|
665 | m_pToggleButton->show();
|
---|
666 | }
|
---|
667 |
|
---|
668 | /* Prepare body indent: */
|
---|
669 | iPreviousVerticalIndent = 2 * iMarginV + iFullHeaderHeight;
|
---|
670 |
|
---|
671 | /* Adjust scroll-view geometry: */
|
---|
672 | QSize itemSize = size().toSize();
|
---|
673 | itemSize.setHeight(itemSize.height() - iPreviousVerticalIndent);
|
---|
674 | /* Adjust favorite children container: */
|
---|
675 | m_pContainerFavorite->resize(itemSize.width() - iParentIndent, m_pContainerFavorite->minimumSizeHint().height());
|
---|
676 | m_pContainerFavorite->setPos(iParentIndent, iPreviousVerticalIndent);
|
---|
677 | iPreviousVerticalIndent += m_pContainerFavorite->minimumSizeHint().height();
|
---|
678 | /* Adjust other children scroll-area: */
|
---|
679 | m_pScrollArea->resize(itemSize.width() - iParentIndent, itemSize.height() - m_pContainerFavorite->minimumSizeHint().height());
|
---|
680 | m_pScrollArea->setPos(iParentIndent, iPreviousVerticalIndent);
|
---|
681 | }
|
---|
682 |
|
---|
683 | /* No body for closed group: */
|
---|
684 | if (isClosed())
|
---|
685 | {
|
---|
686 | m_pContainerFavorite->hide();
|
---|
687 | m_pScrollArea->hide();
|
---|
688 | }
|
---|
689 | /* Body for opened group: */
|
---|
690 | else
|
---|
691 | {
|
---|
692 | m_pContainerFavorite->show();
|
---|
693 | m_pScrollArea->show();
|
---|
694 | foreach (UIChooserItem *pItem, items())
|
---|
695 | pItem->updateLayout();
|
---|
696 | }
|
---|
697 | }
|
---|
698 |
|
---|
699 | int UIChooserItemGroup::minimumWidthHint() const
|
---|
700 | {
|
---|
701 | return minimumWidthHintForGroup(isOpened());
|
---|
702 | }
|
---|
703 |
|
---|
704 | int UIChooserItemGroup::minimumHeightHint() const
|
---|
705 | {
|
---|
706 | return minimumHeightHintForGroup(isOpened());
|
---|
707 | }
|
---|
708 |
|
---|
709 | QSizeF UIChooserItemGroup::sizeHint(Qt::SizeHint enmWhich, const QSizeF &constraint /* = QSizeF() */) const
|
---|
710 | {
|
---|
711 | /* If Qt::MinimumSize requested: */
|
---|
712 | if (enmWhich == Qt::MinimumSize)
|
---|
713 | return minimumSizeHintForGroup(isOpened());
|
---|
714 | /* Else call to base-class: */
|
---|
715 | return UIChooserItem::sizeHint(enmWhich, constraint);
|
---|
716 | }
|
---|
717 |
|
---|
718 | QPixmap UIChooserItemGroup::toPixmap()
|
---|
719 | {
|
---|
720 | /* Ask item to paint itself into pixmap: */
|
---|
721 | qreal dDpr = gpManager->windowHandle()->devicePixelRatio();
|
---|
722 | QSize actualSize = size().toSize();
|
---|
723 | QPixmap pixmap(actualSize * dDpr);
|
---|
724 | pixmap.setDevicePixelRatio(dDpr);
|
---|
725 | QPainter painter(&pixmap);
|
---|
726 | QStyleOptionGraphicsItem options;
|
---|
727 | options.rect = QRect(QPoint(0, 0), actualSize);
|
---|
728 | paint(&painter, &options);
|
---|
729 | return pixmap;
|
---|
730 | }
|
---|
731 |
|
---|
732 | bool UIChooserItemGroup::isDropAllowed(QGraphicsSceneDragDropEvent *pEvent, UIChooserItemDragToken where) const
|
---|
733 | {
|
---|
734 | /* No drops while saving groups: */
|
---|
735 | if (model()->isGroupSavingInProgress())
|
---|
736 | return false;
|
---|
737 | /* If drag token is shown, its up to parent to decide: */
|
---|
738 | if (where != UIChooserItemDragToken_Off)
|
---|
739 | return parentItem()->isDropAllowed(pEvent);
|
---|
740 |
|
---|
741 | /* Else we should check mime format: */
|
---|
742 | const QMimeData *pMimeData = pEvent->mimeData();
|
---|
743 | if (pMimeData->hasFormat(UIChooserItemGroup::className()))
|
---|
744 | {
|
---|
745 | /* Get passed group-item: */
|
---|
746 | const UIChooserItemMimeData *pCastedMimeData = qobject_cast<const UIChooserItemMimeData*>(pMimeData);
|
---|
747 | AssertPtrReturn(pCastedMimeData, false);
|
---|
748 | UIChooserItem *pItem = pCastedMimeData->item();
|
---|
749 | AssertPtrReturn(pItem, false);
|
---|
750 | UIChooserItemGroup *pGroupItem = pItem->toGroupItem();
|
---|
751 | AssertPtrReturn(pGroupItem, false);
|
---|
752 |
|
---|
753 | /* For local items: */
|
---|
754 | if ( groupType() == UIChooserNodeGroupType_Local
|
---|
755 | && pGroupItem->groupType() == UIChooserNodeGroupType_Local)
|
---|
756 | {
|
---|
757 | /* Make sure passed machine isn't immutable within own group: */
|
---|
758 | if ( pGroupItem->isContainsLockedMachine()
|
---|
759 | && !m_groupItems.contains(pItem))
|
---|
760 | return false;
|
---|
761 | /* Make sure passed group is not 'this': */
|
---|
762 | if (pItem == this)
|
---|
763 | return false;
|
---|
764 | /* Make sure passed group is not among our parents: */
|
---|
765 | const UIChooserItem *pTestedItem = this;
|
---|
766 | while (UIChooserItem *pParentOfTestedWidget = pTestedItem->parentItem())
|
---|
767 | {
|
---|
768 | if (pItem == pParentOfTestedWidget)
|
---|
769 | return false;
|
---|
770 | pTestedItem = pParentOfTestedWidget;
|
---|
771 | }
|
---|
772 |
|
---|
773 | /* Allow finally: */
|
---|
774 | return true;
|
---|
775 | }
|
---|
776 | /* For profiles inside provider and providers inside root group: */
|
---|
777 | else
|
---|
778 | if ( ( groupType() == UIChooserNodeGroupType_Provider
|
---|
779 | && pGroupItem->groupType() == UIChooserNodeGroupType_Profile)
|
---|
780 | || ( groupType() == UIChooserNodeGroupType_Local
|
---|
781 | && pGroupItem->groupType() == UIChooserNodeGroupType_Provider))
|
---|
782 | {
|
---|
783 | /* Make sure passed item is ours: */
|
---|
784 | return m_groupItems.contains(pItem);
|
---|
785 | }
|
---|
786 | }
|
---|
787 | else if (pMimeData->hasFormat(UIChooserItemMachine::className()))
|
---|
788 | {
|
---|
789 | /* Get passed machine-item: */
|
---|
790 | const UIChooserItemMimeData *pCastedMimeData = qobject_cast<const UIChooserItemMimeData*>(pMimeData);
|
---|
791 | AssertPtrReturn(pCastedMimeData, false);
|
---|
792 | UIChooserItem *pItem = pCastedMimeData->item();
|
---|
793 | AssertPtrReturn(pItem, false);
|
---|
794 | UIChooserItemMachine *pMachineItem = pItem->toMachineItem();
|
---|
795 | AssertPtrReturn(pMachineItem, false);
|
---|
796 |
|
---|
797 | /* For local items: */
|
---|
798 | if ( groupType() == UIChooserNodeGroupType_Local
|
---|
799 | && pMachineItem->cacheType() == UIVirtualMachineItemType_Local)
|
---|
800 | {
|
---|
801 | /* Make sure passed machine isn't immutable within own group: */
|
---|
802 | if ( pMachineItem->isLockedMachine()
|
---|
803 | && !m_machineItems.contains(pItem))
|
---|
804 | return false;
|
---|
805 | switch (pEvent->proposedAction())
|
---|
806 | {
|
---|
807 | case Qt::MoveAction:
|
---|
808 | {
|
---|
809 | /* Make sure passed item is ours or there is no other item with such id: */
|
---|
810 | return m_machineItems.contains(pItem) || !isContainsMachine(pMachineItem->id());
|
---|
811 | }
|
---|
812 | case Qt::CopyAction:
|
---|
813 | {
|
---|
814 | /* Make sure there is no other item with such id: */
|
---|
815 | return !isContainsMachine(pMachineItem->id());
|
---|
816 | }
|
---|
817 | default:
|
---|
818 | break;
|
---|
819 | }
|
---|
820 | }
|
---|
821 | /* For cloud items: */
|
---|
822 | else
|
---|
823 | if ( groupType() == UIChooserNodeGroupType_Profile
|
---|
824 | && pMachineItem->cacheType() == UIVirtualMachineItemType_CloudReal)
|
---|
825 | {
|
---|
826 | /* Make sure passed item is ours: */
|
---|
827 | return m_machineItems.contains(pItem);
|
---|
828 | }
|
---|
829 | }
|
---|
830 | /* That was invalid mime: */
|
---|
831 | return false;
|
---|
832 | }
|
---|
833 |
|
---|
834 | void UIChooserItemGroup::processDrop(QGraphicsSceneDragDropEvent *pEvent, UIChooserItem *pFromWho, UIChooserItemDragToken where)
|
---|
835 | {
|
---|
836 | /* Get mime: */
|
---|
837 | const QMimeData *pMime = pEvent->mimeData();
|
---|
838 | /* Check mime format: */
|
---|
839 | if (pMime->hasFormat(UIChooserItemGroup::className()))
|
---|
840 | {
|
---|
841 | switch (pEvent->proposedAction())
|
---|
842 | {
|
---|
843 | case Qt::MoveAction:
|
---|
844 | case Qt::CopyAction:
|
---|
845 | {
|
---|
846 | /* Remember scene: */
|
---|
847 | UIChooserModel *pModel = model();
|
---|
848 |
|
---|
849 | /* Get passed group-item: */
|
---|
850 | const UIChooserItemMimeData *pCastedMime = qobject_cast<const UIChooserItemMimeData*>(pMime);
|
---|
851 | AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIChooserItemMimeData!"));
|
---|
852 | UIChooserNode *pNode = pCastedMime->item()->node();
|
---|
853 |
|
---|
854 | /* Check if we have position information: */
|
---|
855 | int iPosition = m_groupItems.size();
|
---|
856 | if (pFromWho && where != UIChooserItemDragToken_Off)
|
---|
857 | {
|
---|
858 | /* Make sure sender item if our child: */
|
---|
859 | AssertMsg(m_groupItems.contains(pFromWho), ("Sender item is NOT our child!"));
|
---|
860 | if (m_groupItems.contains(pFromWho))
|
---|
861 | {
|
---|
862 | iPosition = m_groupItems.indexOf(pFromWho);
|
---|
863 | if (where == UIChooserItemDragToken_Down)
|
---|
864 | ++iPosition;
|
---|
865 | }
|
---|
866 | }
|
---|
867 |
|
---|
868 | /* Copy passed group-item into this group: */
|
---|
869 | UIChooserNodeGroup *pNewGroupNode = new UIChooserNodeGroup(node(), iPosition, pNode->toGroupNode());
|
---|
870 | UIChooserItemGroup *pNewGroupItem = new UIChooserItemGroup(this, pNewGroupNode);
|
---|
871 | if (isClosed())
|
---|
872 | open(false);
|
---|
873 |
|
---|
874 | /* If proposed action is 'move': */
|
---|
875 | if (pEvent->proposedAction() == Qt::MoveAction)
|
---|
876 | {
|
---|
877 | /* Delete passed item: */
|
---|
878 | delete pNode;
|
---|
879 | }
|
---|
880 |
|
---|
881 | /* Update model: */
|
---|
882 | pModel->wipeOutEmptyGroups();
|
---|
883 | pModel->updateNavigationItemList();
|
---|
884 | pModel->updateLayout();
|
---|
885 | pModel->setSelectedItem(pNewGroupItem);
|
---|
886 | pModel->saveGroups();
|
---|
887 | break;
|
---|
888 | }
|
---|
889 | default:
|
---|
890 | break;
|
---|
891 | }
|
---|
892 | }
|
---|
893 | else if (pMime->hasFormat(UIChooserItemMachine::className()))
|
---|
894 | {
|
---|
895 | switch (pEvent->proposedAction())
|
---|
896 | {
|
---|
897 | case Qt::MoveAction:
|
---|
898 | case Qt::CopyAction:
|
---|
899 | {
|
---|
900 | /* Remember scene: */
|
---|
901 | UIChooserModel *pModel = model();
|
---|
902 |
|
---|
903 | /* Get passed machine-item: */
|
---|
904 | const UIChooserItemMimeData *pCastedMime = qobject_cast<const UIChooserItemMimeData*>(pMime);
|
---|
905 | AssertMsg(pCastedMime, ("Can't cast passed mime-data to UIChooserItemMimeData!"));
|
---|
906 | UIChooserNode *pNode = pCastedMime->item()->node();
|
---|
907 |
|
---|
908 | /* Check if we have position information: */
|
---|
909 | int iPosition = m_machineItems.size();
|
---|
910 | if (pFromWho && where != UIChooserItemDragToken_Off)
|
---|
911 | {
|
---|
912 | /* Make sure sender item if our child: */
|
---|
913 | AssertMsg(m_machineItems.contains(pFromWho), ("Sender item is NOT our child!"));
|
---|
914 | if (m_machineItems.contains(pFromWho))
|
---|
915 | {
|
---|
916 | iPosition = m_machineItems.indexOf(pFromWho);
|
---|
917 | if (where == UIChooserItemDragToken_Down)
|
---|
918 | ++iPosition;
|
---|
919 | }
|
---|
920 | }
|
---|
921 |
|
---|
922 | /* Copy passed machine-item into this group: */
|
---|
923 | UIChooserNodeMachine *pNewMachineNode = new UIChooserNodeMachine(node(), iPosition, pNode->toMachineNode());
|
---|
924 | UIChooserItemMachine *pNewMachineItem = new UIChooserItemMachine(this, pNewMachineNode);
|
---|
925 | if (isClosed())
|
---|
926 | open(false);
|
---|
927 |
|
---|
928 | /* If proposed action is 'move': */
|
---|
929 | if (pEvent->proposedAction() == Qt::MoveAction)
|
---|
930 | {
|
---|
931 | /* Delete passed item: */
|
---|
932 | delete pNode;
|
---|
933 | }
|
---|
934 |
|
---|
935 | /* Update model: */
|
---|
936 | pModel->wipeOutEmptyGroups();
|
---|
937 | pModel->updateNavigationItemList();
|
---|
938 | pModel->updateLayout();
|
---|
939 | pModel->setSelectedItem(pNewMachineItem);
|
---|
940 | pModel->saveGroups();
|
---|
941 | break;
|
---|
942 | }
|
---|
943 | default:
|
---|
944 | break;
|
---|
945 | }
|
---|
946 | }
|
---|
947 | }
|
---|
948 |
|
---|
949 | void UIChooserItemGroup::resetDragToken()
|
---|
950 | {
|
---|
951 | /* Reset drag token for this item: */
|
---|
952 | if (dragTokenPlace() != UIChooserItemDragToken_Off)
|
---|
953 | {
|
---|
954 | setDragTokenPlace(UIChooserItemDragToken_Off);
|
---|
955 | update();
|
---|
956 | }
|
---|
957 | /* Reset drag tokens for all the items: */
|
---|
958 | foreach (UIChooserItem *pItem, items())
|
---|
959 | pItem->resetDragToken();
|
---|
960 | }
|
---|
961 |
|
---|
962 | QMimeData* UIChooserItemGroup::createMimeData()
|
---|
963 | {
|
---|
964 | return new UIChooserItemMimeData(this);
|
---|
965 | }
|
---|
966 |
|
---|
967 | void UIChooserItemGroup::sltHandleWindowRemapped()
|
---|
968 | {
|
---|
969 | /* Update pixmaps: */
|
---|
970 | updatePixmaps();
|
---|
971 | }
|
---|
972 |
|
---|
973 | void UIChooserItemGroup::sltNameEditingFinished()
|
---|
974 | {
|
---|
975 | /* Not for root: */
|
---|
976 | if (isRoot())
|
---|
977 | return;
|
---|
978 |
|
---|
979 | /* Close name-editor: */
|
---|
980 | m_pNameEditorWidget->close();
|
---|
981 |
|
---|
982 | /* Enumerate all the used machine and group names: */
|
---|
983 | QStringList usedNames;
|
---|
984 | foreach (UIChooserItem *pItem, parentItem()->items())
|
---|
985 | {
|
---|
986 | AssertPtrReturnVoid(pItem);
|
---|
987 | if ( pItem->type() == UIChooserNodeType_Machine
|
---|
988 | || ( pItem->type() == UIChooserNodeType_Group
|
---|
989 | && pItem->toGroupItem()->groupType() == UIChooserNodeGroupType_Local))
|
---|
990 | usedNames << pItem->name();
|
---|
991 | }
|
---|
992 | /* If proposed name is empty or not unique, reject it: */
|
---|
993 | QString strNewName = m_pNameEditorWidget->text().trimmed();
|
---|
994 | if (strNewName.isEmpty() || usedNames.contains(strNewName))
|
---|
995 | return;
|
---|
996 |
|
---|
997 | /* We should replace forbidden symbols
|
---|
998 | * with ... well, probably underscores: */
|
---|
999 | strNewName.replace(QRegularExpression("[\\\\/:*?\"<>]"), "_");
|
---|
1000 |
|
---|
1001 | /* Set new name, save settings: */
|
---|
1002 | nodeToGroupType()->setName(strNewName);
|
---|
1003 | model()->saveGroups();
|
---|
1004 | }
|
---|
1005 |
|
---|
1006 | void UIChooserItemGroup::sltGroupToggleStart()
|
---|
1007 | {
|
---|
1008 | /* Not for root: */
|
---|
1009 | if (isRoot())
|
---|
1010 | return;
|
---|
1011 |
|
---|
1012 | /* Toggle started: */
|
---|
1013 | emit sigToggleStarted();
|
---|
1014 |
|
---|
1015 | /* Setup animation: */
|
---|
1016 | updateAnimationParameters();
|
---|
1017 |
|
---|
1018 | /* Group closed, we are opening it: */
|
---|
1019 | if (nodeToGroupType()->isClosed())
|
---|
1020 | {
|
---|
1021 | /* Toggle-state and navigation will be
|
---|
1022 | * updated on toggle-finish signal! */
|
---|
1023 | }
|
---|
1024 | /* Group opened, we are closing it: */
|
---|
1025 | else
|
---|
1026 | {
|
---|
1027 | /* Update toggle-state: */
|
---|
1028 | nodeToGroupType()->close();
|
---|
1029 | /* Update geometry: */
|
---|
1030 | updateGeometry();
|
---|
1031 | /* Update navigation: */
|
---|
1032 | model()->updateNavigationItemList();
|
---|
1033 | /* Relayout model: */
|
---|
1034 | model()->updateLayout();
|
---|
1035 | }
|
---|
1036 | }
|
---|
1037 |
|
---|
1038 | void UIChooserItemGroup::sltGroupToggleFinish(bool fToggled)
|
---|
1039 | {
|
---|
1040 | /* Not for root: */
|
---|
1041 | if (isRoot())
|
---|
1042 | return;
|
---|
1043 |
|
---|
1044 | /* Update toggle-state: */
|
---|
1045 | fToggled ? nodeToGroupType()->open() : nodeToGroupType()->close();
|
---|
1046 | /* Update geometry: */
|
---|
1047 | updateGeometry();
|
---|
1048 | /* Update navigation: */
|
---|
1049 | model()->updateNavigationItemList();
|
---|
1050 | /* Relayout model: */
|
---|
1051 | model()->updateLayout();
|
---|
1052 | /* Update toggle-button tool-tip: */
|
---|
1053 | updateToggleButtonToolTip();
|
---|
1054 | /* Repaint finally: */
|
---|
1055 | update();
|
---|
1056 | /* Save changes: */
|
---|
1057 | model()->saveGroups();
|
---|
1058 |
|
---|
1059 | /* Toggle finished: */
|
---|
1060 | emit sigToggleFinished();
|
---|
1061 | }
|
---|
1062 |
|
---|
1063 | void UIChooserItemGroup::prepare()
|
---|
1064 | {
|
---|
1065 | /* Color tones: */
|
---|
1066 | m_iRootBackgroundDarknessStart = 115;
|
---|
1067 | m_iRootBackgroundDarknessFinal = 150;
|
---|
1068 | m_iItemBackgroundDarknessStart = 100;
|
---|
1069 | m_iItemBackgroundDarknessFinal = 105;
|
---|
1070 | #if defined(VBOX_WS_MAC)
|
---|
1071 | m_iHighlightLightness = 105;
|
---|
1072 | #elif defined(VBOX_WS_WIN)
|
---|
1073 | m_iHighlightLightness = 190;
|
---|
1074 | #else /* !VBOX_WS_MAC && !VBOX_WS_WIN */
|
---|
1075 | m_iHighlightLightness = 105;
|
---|
1076 | #endif /* !VBOX_WS_MAC && !VBOX_WS_WIN */
|
---|
1077 |
|
---|
1078 | /* Prepare self: */
|
---|
1079 | m_nameFont = font();
|
---|
1080 | m_nameFont.setWeight(QFont::Bold);
|
---|
1081 | m_infoFont = font();
|
---|
1082 | m_minimumHeaderSize = QSize(0, 0);
|
---|
1083 |
|
---|
1084 | /* Prepare header widgets of non-root item: */
|
---|
1085 | if (!isRoot())
|
---|
1086 | {
|
---|
1087 | /* Setup toggle-button: */
|
---|
1088 | m_pToggleButton = new UIGraphicsRotatorButton(this, "additionalHeight", isOpened());
|
---|
1089 | if (m_pToggleButton)
|
---|
1090 | {
|
---|
1091 | m_pToggleButton->hide();
|
---|
1092 | connect(m_pToggleButton, &UIGraphicsRotatorButton::sigRotationStart,
|
---|
1093 | this, &UIChooserItemGroup::sltGroupToggleStart);
|
---|
1094 | connect(m_pToggleButton, &UIGraphicsRotatorButton::sigRotationFinish,
|
---|
1095 | this, &UIChooserItemGroup::sltGroupToggleFinish);
|
---|
1096 | }
|
---|
1097 | m_toggleButtonSize = m_pToggleButton ? m_pToggleButton->minimumSizeHint().toSize() : QSize(0, 0);
|
---|
1098 |
|
---|
1099 | /* Setup name-editor: */
|
---|
1100 | m_pNameEditorWidget = new UIEditorGroupRename(name());
|
---|
1101 | if (m_pNameEditorWidget)
|
---|
1102 | {
|
---|
1103 | m_pNameEditorWidget->setFont(m_nameFont);
|
---|
1104 | connect(m_pNameEditorWidget, &UIEditorGroupRename::sigEditingFinished,
|
---|
1105 | this, &UIChooserItemGroup::sltNameEditingFinished);
|
---|
1106 | }
|
---|
1107 | }
|
---|
1108 |
|
---|
1109 | /* Prepare favorite children container: */
|
---|
1110 | m_pContainerFavorite = new QIGraphicsWidget(this);
|
---|
1111 | if (m_pContainerFavorite)
|
---|
1112 | {
|
---|
1113 | /* Make it always above other children scroll-area: */
|
---|
1114 | m_pContainerFavorite->setZValue(1);
|
---|
1115 |
|
---|
1116 | /* Prepare favorite children layout: */
|
---|
1117 | m_pLayoutFavorite = new QGraphicsLinearLayout(Qt::Vertical, m_pContainerFavorite);
|
---|
1118 | if (m_pLayoutFavorite)
|
---|
1119 | {
|
---|
1120 | m_pLayoutFavorite->setContentsMargins(0, 0, 0, 0);
|
---|
1121 | m_pLayoutFavorite->setSpacing(0);
|
---|
1122 | }
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 | /* Prepare scroll-area: */
|
---|
1126 | m_pScrollArea = new UIGraphicsScrollArea(Qt::Vertical, this);
|
---|
1127 | if (m_pScrollArea)
|
---|
1128 | {
|
---|
1129 | /* Prepare container: */
|
---|
1130 | m_pContainer = new QIGraphicsWidget;
|
---|
1131 | if (m_pContainer)
|
---|
1132 | {
|
---|
1133 | /* Prepare layout: */
|
---|
1134 | m_pLayout = new QGraphicsLinearLayout(Qt::Vertical, m_pContainer);
|
---|
1135 | if (m_pLayout)
|
---|
1136 | {
|
---|
1137 | m_pLayout->setContentsMargins(0, 0, 0, 0);
|
---|
1138 | m_pLayout->setSpacing(0);
|
---|
1139 |
|
---|
1140 | /* Prepare global layout: */
|
---|
1141 | m_pLayoutGlobal = new QGraphicsLinearLayout(Qt::Vertical);
|
---|
1142 | if (m_pLayoutGlobal)
|
---|
1143 | {
|
---|
1144 | m_pLayoutGlobal->setContentsMargins(0, 0, 0, 0);
|
---|
1145 | m_pLayoutGlobal->setSpacing(1);
|
---|
1146 | m_pLayout->addItem(m_pLayoutGlobal);
|
---|
1147 | }
|
---|
1148 |
|
---|
1149 | /* Prepare group layout: */
|
---|
1150 | m_pLayoutGroup = new QGraphicsLinearLayout(Qt::Vertical);
|
---|
1151 | if (m_pLayoutGroup)
|
---|
1152 | {
|
---|
1153 | m_pLayoutGroup->setContentsMargins(0, 0, 0, 0);
|
---|
1154 | m_pLayoutGroup->setSpacing(1);
|
---|
1155 | m_pLayout->addItem(m_pLayoutGroup);
|
---|
1156 | }
|
---|
1157 |
|
---|
1158 | /* Prepare machine layout: */
|
---|
1159 | m_pLayoutMachine = new QGraphicsLinearLayout(Qt::Vertical);
|
---|
1160 | if (m_pLayoutMachine)
|
---|
1161 | {
|
---|
1162 | m_pLayoutMachine->setContentsMargins(0, 0, 0, 0);
|
---|
1163 | m_pLayoutMachine->setSpacing(1);
|
---|
1164 | m_pLayout->addItem(m_pLayoutMachine);
|
---|
1165 | }
|
---|
1166 | }
|
---|
1167 |
|
---|
1168 | /* Assign to scroll-area: */
|
---|
1169 | m_pScrollArea->setViewport(m_pContainer);
|
---|
1170 | }
|
---|
1171 | }
|
---|
1172 |
|
---|
1173 | /* Add item directly to the scene (if passed): */
|
---|
1174 | if (m_pScene)
|
---|
1175 | m_pScene->addItem(this);
|
---|
1176 | /* Add item to the parent instead (if passed),
|
---|
1177 | * it will be added to the scene indirectly: */
|
---|
1178 | else if (parentItem())
|
---|
1179 | parentItem()->addItem(this, isFavorite(), position());
|
---|
1180 | /* Otherwise sombody forgot to pass scene or parent. */
|
---|
1181 | else
|
---|
1182 | AssertFailedReturnVoid();
|
---|
1183 |
|
---|
1184 | /* Copy contents: */
|
---|
1185 | copyContents(nodeToGroupType());
|
---|
1186 |
|
---|
1187 | /* Apply language settings: */
|
---|
1188 | sltRetranslateUI();
|
---|
1189 | connect(&translationEventListener(), &UITranslationEventListener::sigRetranslateUI,
|
---|
1190 | this, &UIChooserItemGroup::sltRetranslateUI);
|
---|
1191 |
|
---|
1192 | /* Initialize non-root items: */
|
---|
1193 | if (!isRoot())
|
---|
1194 | {
|
---|
1195 | updatePixmaps();
|
---|
1196 | updateItemCountInfo();
|
---|
1197 | updateVisibleName();
|
---|
1198 | updateToolTip();
|
---|
1199 | }
|
---|
1200 |
|
---|
1201 | /* Configure connections: */
|
---|
1202 | connect(this, &UIChooserItemGroup::sigMinimumWidthHintChanged,
|
---|
1203 | model(), &UIChooserModel::sigRootItemMinimumWidthHintChanged);
|
---|
1204 | if (!isRoot())
|
---|
1205 | {
|
---|
1206 | /* Non-root items can be toggled: */
|
---|
1207 | connect(this, &UIChooserItemGroup::sigToggleStarted,
|
---|
1208 | model(), &UIChooserModel::sigToggleStarted);
|
---|
1209 | connect(this, &UIChooserItemGroup::sigToggleFinished,
|
---|
1210 | model(), &UIChooserModel::sigToggleFinished,
|
---|
1211 | Qt::QueuedConnection);
|
---|
1212 | /* Non-root items requires pixmap updates: */
|
---|
1213 | connect(gpManager, &UIVirtualBoxManager::sigWindowRemapped,
|
---|
1214 | this, &UIChooserItemGroup::sltHandleWindowRemapped);
|
---|
1215 | }
|
---|
1216 |
|
---|
1217 | /* Invalidate minimum width hint
|
---|
1218 | * after we isntalled listener: */
|
---|
1219 | m_iPreviousMinimumWidthHint = 0;
|
---|
1220 | /* Update geometry finally: */
|
---|
1221 | updateGeometry();
|
---|
1222 | }
|
---|
1223 |
|
---|
1224 | void UIChooserItemGroup::cleanup()
|
---|
1225 | {
|
---|
1226 | /* Delete group name editor: */
|
---|
1227 | delete m_pNameEditorWidget;
|
---|
1228 | m_pNameEditorWidget = 0;
|
---|
1229 |
|
---|
1230 | /* Delete all the items: */
|
---|
1231 | while (!m_groupItems.isEmpty()) { delete m_groupItems.last(); }
|
---|
1232 | while (!m_globalItems.isEmpty()) { delete m_globalItems.last(); }
|
---|
1233 | while (!m_machineItems.isEmpty()) { delete m_machineItems.last(); }
|
---|
1234 |
|
---|
1235 | /* If that item is current: */
|
---|
1236 | if (model()->currentItem() == this)
|
---|
1237 | {
|
---|
1238 | /* Unset current-item: */
|
---|
1239 | model()->setCurrentItem(0);
|
---|
1240 | }
|
---|
1241 | /* If that item is in selection list: */
|
---|
1242 | if (model()->selectedItems().contains(this))
|
---|
1243 | {
|
---|
1244 | /* Remove item from the selection list: */
|
---|
1245 | model()->removeFromSelectedItems(this);
|
---|
1246 | }
|
---|
1247 | /* If that item is in navigation list: */
|
---|
1248 | if (model()->navigationItems().contains(this))
|
---|
1249 | {
|
---|
1250 | /* Remove item from the navigation list: */
|
---|
1251 | model()->removeFromNavigationItems(this);
|
---|
1252 | }
|
---|
1253 |
|
---|
1254 | /* Remove item from the parent: */
|
---|
1255 | if (parentItem())
|
---|
1256 | parentItem()->removeItem(this);
|
---|
1257 | }
|
---|
1258 |
|
---|
1259 | QVariant UIChooserItemGroup::data(int iKey) const
|
---|
1260 | {
|
---|
1261 | /* Provide other members with required data: */
|
---|
1262 | switch (iKey)
|
---|
1263 | {
|
---|
1264 | /* Layout hints: */
|
---|
1265 | case GroupItemData_MarginHL: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
|
---|
1266 | case GroupItemData_MarginHR: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 4 * 5;
|
---|
1267 | case GroupItemData_MarginV: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
|
---|
1268 | case GroupItemData_HeaderSpacing: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
|
---|
1269 | case GroupItemData_ChildrenSpacing: return 1;
|
---|
1270 | case GroupItemData_ParentIndent: return QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 2;
|
---|
1271 |
|
---|
1272 | /* Default: */
|
---|
1273 | default: break;
|
---|
1274 | }
|
---|
1275 | return QVariant();
|
---|
1276 | }
|
---|
1277 |
|
---|
1278 | int UIChooserItemGroup::additionalHeight() const
|
---|
1279 | {
|
---|
1280 | return m_iAdditionalHeight;
|
---|
1281 | }
|
---|
1282 |
|
---|
1283 | void UIChooserItemGroup::setAdditionalHeight(int iAdditionalHeight)
|
---|
1284 | {
|
---|
1285 | m_iAdditionalHeight = iAdditionalHeight;
|
---|
1286 | updateGeometry();
|
---|
1287 | model()->updateLayout();
|
---|
1288 | }
|
---|
1289 |
|
---|
1290 | void UIChooserItemGroup::updateAnimationParameters()
|
---|
1291 | {
|
---|
1292 | /* Only for item with button: */
|
---|
1293 | if (!m_pToggleButton)
|
---|
1294 | return;
|
---|
1295 |
|
---|
1296 | /* Recalculate animation parameters: */
|
---|
1297 | QSizeF openedSize = minimumSizeHintForGroup(true);
|
---|
1298 | QSizeF closedSize = minimumSizeHintForGroup(false);
|
---|
1299 | int iAdditionalHeight = (int)(openedSize.height() - closedSize.height());
|
---|
1300 | m_pToggleButton->setAnimationRange(0, iAdditionalHeight);
|
---|
1301 | }
|
---|
1302 |
|
---|
1303 | void UIChooserItemGroup::updateToggleButtonToolTip()
|
---|
1304 | {
|
---|
1305 | /* Only for item with button: */
|
---|
1306 | if (!m_pToggleButton)
|
---|
1307 | return;
|
---|
1308 |
|
---|
1309 | /* Update toggle-button tool-tip: */
|
---|
1310 | m_pToggleButton->setToolTip(isOpened() ? tr("Collapse group") : tr("Expand group"));
|
---|
1311 | }
|
---|
1312 |
|
---|
1313 | void UIChooserItemGroup::copyContents(UIChooserNodeGroup *pCopyFrom)
|
---|
1314 | {
|
---|
1315 | foreach (UIChooserNode *pNode, pCopyFrom->nodes(UIChooserNodeType_Group))
|
---|
1316 | new UIChooserItemGroup(this, pNode->toGroupNode());
|
---|
1317 | foreach (UIChooserNode *pNode, pCopyFrom->nodes(UIChooserNodeType_Global))
|
---|
1318 | new UIChooserItemGlobal(this, pNode->toGlobalNode());
|
---|
1319 | foreach (UIChooserNode *pNode, pCopyFrom->nodes(UIChooserNodeType_Machine))
|
---|
1320 | new UIChooserItemMachine(this, pNode->toMachineNode());
|
---|
1321 | }
|
---|
1322 |
|
---|
1323 | bool UIChooserItemGroup::isContainsMachine(const QUuid &uId) const
|
---|
1324 | {
|
---|
1325 | /* Check each machine-item: */
|
---|
1326 | foreach (UIChooserItem *pItem, m_machineItems)
|
---|
1327 | {
|
---|
1328 | /* Make sure it's really machine node: */
|
---|
1329 | AssertPtrReturn(pItem, false);
|
---|
1330 | UIChooserItemMachine *pMachineItem = pItem->toMachineItem();
|
---|
1331 | AssertPtrReturn(pMachineItem, false);
|
---|
1332 | if (pMachineItem->id() == uId)
|
---|
1333 | return true;
|
---|
1334 | }
|
---|
1335 | /* Found nothing? */
|
---|
1336 | return false;
|
---|
1337 | }
|
---|
1338 |
|
---|
1339 | bool UIChooserItemGroup::isContainsLockedMachine()
|
---|
1340 | {
|
---|
1341 | /* Check each machine-item: */
|
---|
1342 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Machine))
|
---|
1343 | if (pItem->toMachineItem()->isLockedMachine())
|
---|
1344 | return true;
|
---|
1345 | /* Check each group-item: */
|
---|
1346 | foreach (UIChooserItem *pItem, items(UIChooserNodeType_Group))
|
---|
1347 | if (pItem->toGroupItem()->isContainsLockedMachine())
|
---|
1348 | return true;
|
---|
1349 | /* Found nothing? */
|
---|
1350 | return false;
|
---|
1351 | }
|
---|
1352 |
|
---|
1353 | void UIChooserItemGroup::updateItemCountInfo()
|
---|
1354 | {
|
---|
1355 | /* Not for root item: */
|
---|
1356 | if (isRoot())
|
---|
1357 | return;
|
---|
1358 |
|
---|
1359 | /* Update item info attributes: */
|
---|
1360 | QPaintDevice *pPaintDevice = model()->paintDevice();
|
---|
1361 | QString strInfoGroups = m_groupItems.isEmpty() ? QString() : QString::number(m_groupItems.size());
|
---|
1362 | QString strInfoMachines = m_machineItems.isEmpty() ? QString() : QString::number(m_machineItems.size());
|
---|
1363 | QSize infoSizeGroups = textSize(m_infoFont, pPaintDevice, strInfoGroups);
|
---|
1364 | QSize infoSizeMachines = textSize(m_infoFont, pPaintDevice, strInfoMachines);
|
---|
1365 |
|
---|
1366 | /* Update linked values: */
|
---|
1367 | bool fSomethingChanged = false;
|
---|
1368 | if (m_strInfoGroups != strInfoGroups)
|
---|
1369 | {
|
---|
1370 | m_strInfoGroups = strInfoGroups;
|
---|
1371 | fSomethingChanged = true;
|
---|
1372 | }
|
---|
1373 | if (m_strInfoMachines != strInfoMachines)
|
---|
1374 | {
|
---|
1375 | m_strInfoMachines = strInfoMachines;
|
---|
1376 | fSomethingChanged = true;
|
---|
1377 | }
|
---|
1378 | if (m_infoSizeGroups != infoSizeGroups)
|
---|
1379 | {
|
---|
1380 | m_infoSizeGroups = infoSizeGroups;
|
---|
1381 | fSomethingChanged = true;
|
---|
1382 | }
|
---|
1383 | if (m_infoSizeMachines != infoSizeMachines)
|
---|
1384 | {
|
---|
1385 | m_infoSizeMachines = infoSizeMachines;
|
---|
1386 | fSomethingChanged = true;
|
---|
1387 | }
|
---|
1388 | if (fSomethingChanged)
|
---|
1389 | {
|
---|
1390 | updateVisibleName();
|
---|
1391 | updateMinimumHeaderSize();
|
---|
1392 | }
|
---|
1393 | }
|
---|
1394 |
|
---|
1395 | int UIChooserItemGroup::minimumWidthHintForGroup(bool fGroupOpened) const
|
---|
1396 | {
|
---|
1397 | /* Calculating proposed width: */
|
---|
1398 | int iProposedWidth = 0;
|
---|
1399 |
|
---|
1400 | /* For root item: */
|
---|
1401 | if (isRoot())
|
---|
1402 | {
|
---|
1403 | /* Main root-item always takes body into account: */
|
---|
1404 | if (node()->hasNodes())
|
---|
1405 | {
|
---|
1406 | /* We have to take maximum children width into account: */
|
---|
1407 | iProposedWidth = qMax(m_pContainerFavorite->minimumSizeHint().width(),
|
---|
1408 | m_pContainer->minimumSizeHint().width());
|
---|
1409 | }
|
---|
1410 | }
|
---|
1411 | /* For other items: */
|
---|
1412 | else
|
---|
1413 | {
|
---|
1414 | /* Prepare variables: */
|
---|
1415 | const int iMarginHL = data(GroupItemData_MarginHL).toInt();
|
---|
1416 | const int iMarginHR = data(GroupItemData_MarginHR).toInt();
|
---|
1417 |
|
---|
1418 | /* Basically we have to take header width into account: */
|
---|
1419 | iProposedWidth += m_minimumHeaderSize.width();
|
---|
1420 |
|
---|
1421 | /* But if group-item is opened: */
|
---|
1422 | if (fGroupOpened)
|
---|
1423 | {
|
---|
1424 | /* We have to take maximum children width into account: */
|
---|
1425 | iProposedWidth = qMax(m_pContainerFavorite->minimumSizeHint().width(),
|
---|
1426 | m_pContainer->minimumSizeHint().width());
|
---|
1427 | }
|
---|
1428 |
|
---|
1429 | /* And 2 margins at last - left and right: */
|
---|
1430 | iProposedWidth += iMarginHL + iMarginHR;
|
---|
1431 | }
|
---|
1432 |
|
---|
1433 | /* Return result: */
|
---|
1434 | return iProposedWidth;
|
---|
1435 | }
|
---|
1436 |
|
---|
1437 | int UIChooserItemGroup::minimumHeightHintForGroup(bool fGroupOpened) const
|
---|
1438 | {
|
---|
1439 | /* Calculating proposed height: */
|
---|
1440 | int iProposedHeight = 0;
|
---|
1441 |
|
---|
1442 | /* For root item: */
|
---|
1443 | if (isRoot())
|
---|
1444 | {
|
---|
1445 | /* Main root-item always takes body into account: */
|
---|
1446 | if (node()->hasNodes())
|
---|
1447 | {
|
---|
1448 | /* Prepare variables: */
|
---|
1449 | const int iSpacingV = data(GroupItemData_ChildrenSpacing).toInt();
|
---|
1450 |
|
---|
1451 | /* We have to take maximum children height into account: */
|
---|
1452 | iProposedHeight += m_pContainerFavorite->minimumSizeHint().height();
|
---|
1453 | iProposedHeight += m_pContainer->minimumSizeHint().height();
|
---|
1454 | iProposedHeight += iSpacingV;
|
---|
1455 | }
|
---|
1456 | }
|
---|
1457 | /* For other items: */
|
---|
1458 | else
|
---|
1459 | {
|
---|
1460 | /* Prepare variables: */
|
---|
1461 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
1462 |
|
---|
1463 | /* Group-item header have 2 margins - top and bottom: */
|
---|
1464 | iProposedHeight += 2 * iMarginV;
|
---|
1465 | /* And header content height to take into account: */
|
---|
1466 | iProposedHeight += m_minimumHeaderSize.height();
|
---|
1467 |
|
---|
1468 | /* But if group-item is opened: */
|
---|
1469 | if (fGroupOpened)
|
---|
1470 | {
|
---|
1471 | /* We have to take maximum children height into account: */
|
---|
1472 | iProposedHeight += m_pContainerFavorite->minimumSizeHint().height();
|
---|
1473 | iProposedHeight += m_pContainer->minimumSizeHint().height();
|
---|
1474 | }
|
---|
1475 |
|
---|
1476 | /* Finally, additional height during animation: */
|
---|
1477 | if (!fGroupOpened && m_pToggleButton && m_pToggleButton->isAnimationRunning())
|
---|
1478 | iProposedHeight += m_iAdditionalHeight;
|
---|
1479 | }
|
---|
1480 |
|
---|
1481 | /* Return result: */
|
---|
1482 | return iProposedHeight;
|
---|
1483 | }
|
---|
1484 |
|
---|
1485 | QSizeF UIChooserItemGroup::minimumSizeHintForGroup(bool fGroupOpened) const
|
---|
1486 | {
|
---|
1487 | return QSizeF(minimumWidthHintForGroup(fGroupOpened), minimumHeightHintForGroup(fGroupOpened));
|
---|
1488 | }
|
---|
1489 |
|
---|
1490 | void UIChooserItemGroup::updateVisibleName()
|
---|
1491 | {
|
---|
1492 | /* Not for root item: */
|
---|
1493 | if (isRoot())
|
---|
1494 | return;
|
---|
1495 |
|
---|
1496 | /* Prepare variables: */
|
---|
1497 | int iMarginHL = data(GroupItemData_MarginHL).toInt();
|
---|
1498 | int iMarginHR = data(GroupItemData_MarginHR).toInt();
|
---|
1499 | int iHeaderSpacing = data(GroupItemData_HeaderSpacing).toInt();
|
---|
1500 | int iToggleButtonWidth = m_toggleButtonSize.width();
|
---|
1501 | int iGroupPixmapWidth = m_pixmapSizeGroups.width();
|
---|
1502 | int iMachinePixmapWidth = m_pixmapSizeMachines.width();
|
---|
1503 | int iGroupCountTextWidth = m_infoSizeGroups.width();
|
---|
1504 | int iMachineCountTextWidth = m_infoSizeMachines.width();
|
---|
1505 | int iMaximumWidth = (int)geometry().width();
|
---|
1506 |
|
---|
1507 | /* Left margin: */
|
---|
1508 | iMaximumWidth -= iMarginHL;
|
---|
1509 | /* Button width: */
|
---|
1510 | if (!isRoot())
|
---|
1511 | iMaximumWidth -= iToggleButtonWidth;
|
---|
1512 | /* Spacing between button and name: */
|
---|
1513 | iMaximumWidth -= iHeaderSpacing;
|
---|
1514 | if (isHovered())
|
---|
1515 | {
|
---|
1516 | /* Spacing between name and info: */
|
---|
1517 | iMaximumWidth -= iHeaderSpacing;
|
---|
1518 | /* Group info width: */
|
---|
1519 | if (!m_groupItems.isEmpty())
|
---|
1520 | iMaximumWidth -= (iGroupPixmapWidth + iGroupCountTextWidth);
|
---|
1521 | /* Machine info width: */
|
---|
1522 | if (!m_machineItems.isEmpty())
|
---|
1523 | iMaximumWidth -= (iMachinePixmapWidth + iMachineCountTextWidth);
|
---|
1524 | }
|
---|
1525 | /* Right margin: */
|
---|
1526 | iMaximumWidth -= iMarginHR;
|
---|
1527 | /* Calculate new visible name and name-size: */
|
---|
1528 | QPaintDevice *pPaintDevice = model()->paintDevice();
|
---|
1529 | QString strVisibleName = compressText(m_nameFont, pPaintDevice, name(), iMaximumWidth);
|
---|
1530 | QSize visibleNameSize = textSize(m_nameFont, pPaintDevice, strVisibleName);
|
---|
1531 |
|
---|
1532 | /* Update linked values: */
|
---|
1533 | if (m_visibleNameSize != visibleNameSize)
|
---|
1534 | {
|
---|
1535 | m_visibleNameSize = visibleNameSize;
|
---|
1536 | updateGeometry();
|
---|
1537 | }
|
---|
1538 | if (m_strVisibleName != strVisibleName)
|
---|
1539 | {
|
---|
1540 | m_strVisibleName = strVisibleName;
|
---|
1541 | update();
|
---|
1542 | }
|
---|
1543 | }
|
---|
1544 |
|
---|
1545 | void UIChooserItemGroup::updatePixmaps()
|
---|
1546 | {
|
---|
1547 | const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
|
---|
1548 | const qreal fDevicePixelRatio = gpManager->windowHandle() ? gpManager->windowHandle()->devicePixelRatio() : 1;
|
---|
1549 | m_groupsPixmap = UIIconPool::iconSet(":/group_abstract_16px.png").pixmap(QSize(iIconMetric, iIconMetric),
|
---|
1550 | fDevicePixelRatio);
|
---|
1551 | m_machinesPixmap = UIIconPool::iconSet(":/machine_abstract_16px.png").pixmap(QSize(iIconMetric, iIconMetric),
|
---|
1552 | fDevicePixelRatio);
|
---|
1553 | m_pixmapSizeGroups = m_groupsPixmap.size() / m_groupsPixmap.devicePixelRatio();
|
---|
1554 | m_pixmapSizeMachines = m_machinesPixmap.size() / m_machinesPixmap.devicePixelRatio();
|
---|
1555 | }
|
---|
1556 |
|
---|
1557 | void UIChooserItemGroup::updateMinimumHeaderSize()
|
---|
1558 | {
|
---|
1559 | /* Not for root item: */
|
---|
1560 | if (isRoot())
|
---|
1561 | return;
|
---|
1562 |
|
---|
1563 | /* Prepare variables: */
|
---|
1564 | const int iHeaderSpacing = data(GroupItemData_HeaderSpacing).toInt();
|
---|
1565 |
|
---|
1566 | /* Calculate minimum visible name size: */
|
---|
1567 | QPaintDevice *pPaintDevice = model()->paintDevice();
|
---|
1568 | const QFontMetrics fm(m_nameFont, pPaintDevice);
|
---|
1569 | const int iMaximumNameWidth = textWidth(m_nameFont, pPaintDevice, 20);
|
---|
1570 | const QString strCompressedName = compressText(m_nameFont, pPaintDevice, name(), iMaximumNameWidth);
|
---|
1571 | const int iMinimumNameWidth = fm.horizontalAdvance(strCompressedName);
|
---|
1572 | const int iMinimumNameHeight = fm.height();
|
---|
1573 |
|
---|
1574 | /* Calculate minimum width: */
|
---|
1575 | int iHeaderWidth = 0;
|
---|
1576 | /* Button width: */
|
---|
1577 | if (!isRoot())
|
---|
1578 | iHeaderWidth += m_toggleButtonSize.width();
|
---|
1579 | iHeaderWidth += /* Spacing between button and name: */
|
---|
1580 | iHeaderSpacing +
|
---|
1581 | /* Minimum name width: */
|
---|
1582 | iMinimumNameWidth +
|
---|
1583 | /* Spacing between name and info: */
|
---|
1584 | iHeaderSpacing;
|
---|
1585 | /* Group info width: */
|
---|
1586 | if (!m_groupItems.isEmpty())
|
---|
1587 | iHeaderWidth += (m_pixmapSizeGroups.width() + m_infoSizeGroups.width());
|
---|
1588 | /* Machine info width: */
|
---|
1589 | if (!m_machineItems.isEmpty())
|
---|
1590 | iHeaderWidth += (m_pixmapSizeMachines.width() + m_infoSizeMachines.width());
|
---|
1591 |
|
---|
1592 | /* Calculate maximum height: */
|
---|
1593 | QList<int> heights;
|
---|
1594 | /* Button height: */
|
---|
1595 | if (!isRoot())
|
---|
1596 | heights << m_toggleButtonSize.height();
|
---|
1597 | heights /* Minimum name height: */
|
---|
1598 | << iMinimumNameHeight
|
---|
1599 | /* Group info heights: */
|
---|
1600 | << m_pixmapSizeGroups.height() << m_infoSizeGroups.height()
|
---|
1601 | /* Machine info heights: */
|
---|
1602 | << m_pixmapSizeMachines.height() << m_infoSizeMachines.height();
|
---|
1603 | /* Button height: */
|
---|
1604 | int iHeaderHeight = 0;
|
---|
1605 | foreach (int iHeight, heights)
|
---|
1606 | iHeaderHeight = qMax(iHeaderHeight, iHeight);
|
---|
1607 |
|
---|
1608 | /* Calculate new minimum header size: */
|
---|
1609 | const QSize minimumHeaderSize = QSize(iHeaderWidth, iHeaderHeight);
|
---|
1610 |
|
---|
1611 | /* Is there something changed? */
|
---|
1612 | if (m_minimumHeaderSize == minimumHeaderSize)
|
---|
1613 | return;
|
---|
1614 |
|
---|
1615 | /* Update linked values: */
|
---|
1616 | m_minimumHeaderSize = minimumHeaderSize;
|
---|
1617 | updateGeometry();
|
---|
1618 | }
|
---|
1619 |
|
---|
1620 | void UIChooserItemGroup::updateLayoutSpacings()
|
---|
1621 | {
|
---|
1622 | m_pLayout->setItemSpacing(0, m_globalItems.isEmpty() ? 0 : 1);
|
---|
1623 | m_pLayout->setItemSpacing(1, m_groupItems.isEmpty() ? 0 : 1);
|
---|
1624 | m_pLayout->setItemSpacing(2, m_machineItems.isEmpty() ? 0 : 1);
|
---|
1625 | }
|
---|
1626 |
|
---|
1627 | void UIChooserItemGroup::paintBackground(QPainter *pPainter, const QRect &rect)
|
---|
1628 | {
|
---|
1629 | /* Save painter: */
|
---|
1630 | pPainter->save();
|
---|
1631 |
|
---|
1632 | /* Root-item: */
|
---|
1633 | if (isRoot())
|
---|
1634 | {
|
---|
1635 | /* Acquire background color: */
|
---|
1636 | const QColor backgroundColor = QApplication::palette().color(QPalette::Active, QPalette::Window);
|
---|
1637 |
|
---|
1638 | /* Paint default background: */
|
---|
1639 | QLinearGradient gradientDefault(rect.topRight(), rect.bottomLeft());
|
---|
1640 | gradientDefault.setColorAt(0, backgroundColor.darker(m_iRootBackgroundDarknessStart));
|
---|
1641 | gradientDefault.setColorAt(1, backgroundColor.darker(m_iRootBackgroundDarknessFinal));
|
---|
1642 | pPainter->fillRect(rect, gradientDefault);
|
---|
1643 | }
|
---|
1644 | else
|
---|
1645 | {
|
---|
1646 | /* Acquire background color: */
|
---|
1647 | const QColor backgroundColor = model()->selectedItems().contains(this)
|
---|
1648 | ? QApplication::palette().color(QPalette::Active, QPalette::Highlight).lighter(m_iHighlightLightness)
|
---|
1649 | : QApplication::palette().color(QPalette::Active, QPalette::Window);
|
---|
1650 |
|
---|
1651 | /* Paint default background: */
|
---|
1652 | QLinearGradient gradientDefault(rect.topRight(), rect.bottomLeft());
|
---|
1653 | gradientDefault.setColorAt(0, backgroundColor.darker(m_iItemBackgroundDarknessStart));
|
---|
1654 | gradientDefault.setColorAt(1, backgroundColor.darker(m_iItemBackgroundDarknessFinal));
|
---|
1655 | pPainter->fillRect(rect, gradientDefault);
|
---|
1656 |
|
---|
1657 | /* If element is hovered: */
|
---|
1658 | if (animatedValue())
|
---|
1659 | {
|
---|
1660 | /* Calculate header rectangle: */
|
---|
1661 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
1662 | const int iFullHeaderHeight = 2 * iMarginV + m_minimumHeaderSize.height();
|
---|
1663 | QRect headRect = rect;
|
---|
1664 | headRect.setHeight(iFullHeaderHeight);
|
---|
1665 |
|
---|
1666 | /* Acquire header color: */
|
---|
1667 | QColor headColor = backgroundColor.lighter(130);
|
---|
1668 |
|
---|
1669 | /* Paint hovered background: */
|
---|
1670 | QColor hcTone1 = headColor;
|
---|
1671 | QColor hcTone2 = headColor;
|
---|
1672 | hcTone1.setAlpha(255 * animatedValue() / 100);
|
---|
1673 | hcTone2.setAlpha(0);
|
---|
1674 | QLinearGradient gradientHovered(headRect.topLeft(), headRect.bottomLeft());
|
---|
1675 | gradientHovered.setColorAt(0, hcTone1);
|
---|
1676 | gradientHovered.setColorAt(1, hcTone2);
|
---|
1677 | pPainter->fillRect(headRect, gradientHovered);
|
---|
1678 | }
|
---|
1679 |
|
---|
1680 | /* Paint drag token UP? */
|
---|
1681 | if (dragTokenPlace() != UIChooserItemDragToken_Off)
|
---|
1682 | {
|
---|
1683 | QLinearGradient dragTokenGradient;
|
---|
1684 | QRect dragTokenRect = rect;
|
---|
1685 | if (dragTokenPlace() == UIChooserItemDragToken_Up)
|
---|
1686 | {
|
---|
1687 | dragTokenRect.setHeight(5);
|
---|
1688 | dragTokenGradient.setStart(dragTokenRect.bottomLeft());
|
---|
1689 | dragTokenGradient.setFinalStop(dragTokenRect.topLeft());
|
---|
1690 | }
|
---|
1691 | else if (dragTokenPlace() == UIChooserItemDragToken_Down)
|
---|
1692 | {
|
---|
1693 | dragTokenRect.setTopLeft(dragTokenRect.bottomLeft() - QPoint(0, 5));
|
---|
1694 | dragTokenGradient.setStart(dragTokenRect.topLeft());
|
---|
1695 | dragTokenGradient.setFinalStop(dragTokenRect.bottomLeft());
|
---|
1696 | }
|
---|
1697 | dragTokenGradient.setColorAt(0, backgroundColor.darker(dragTokenDarkness()));
|
---|
1698 | dragTokenGradient.setColorAt(1, backgroundColor.darker(dragTokenDarkness() + 40));
|
---|
1699 | pPainter->fillRect(dragTokenRect, dragTokenGradient);
|
---|
1700 | }
|
---|
1701 | }
|
---|
1702 |
|
---|
1703 | /* Restore painter: */
|
---|
1704 | pPainter->restore();
|
---|
1705 | }
|
---|
1706 |
|
---|
1707 | void UIChooserItemGroup::paintFrame(QPainter *pPainter, const QRect &rectangle)
|
---|
1708 | {
|
---|
1709 | /* Not for roots: */
|
---|
1710 | if (isRoot())
|
---|
1711 | return;
|
---|
1712 |
|
---|
1713 | /* Only selected item should have a frame: */
|
---|
1714 | if (!model()->selectedItems().contains(this))
|
---|
1715 | return;
|
---|
1716 |
|
---|
1717 | /* Save painter: */
|
---|
1718 | pPainter->save();
|
---|
1719 |
|
---|
1720 | /* Prepare variables: */
|
---|
1721 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
1722 | const int iParentIndent = data(GroupItemData_ParentIndent).toInt();
|
---|
1723 | const int iFullHeaderHeight = 2 * iMarginV + m_minimumHeaderSize.height();
|
---|
1724 |
|
---|
1725 | /* Prepare color: */
|
---|
1726 | const QColor frameColor = QApplication::palette().color(QPalette::Active, QPalette::Highlight).lighter(m_iHighlightLightness - 40);
|
---|
1727 |
|
---|
1728 | /* Create/assign pen: */
|
---|
1729 | QPen pen(frameColor);
|
---|
1730 | pen.setWidth(0);
|
---|
1731 | pPainter->setPen(pen);
|
---|
1732 |
|
---|
1733 | /* Calculate top rectangle: */
|
---|
1734 | QRect topRect = rectangle;
|
---|
1735 | if (nodeToGroupType()->isOpened())
|
---|
1736 | topRect.setBottom(topRect.top() + iFullHeaderHeight - 1);
|
---|
1737 |
|
---|
1738 | /* Draw borders: */
|
---|
1739 | pPainter->drawLine(rectangle.topLeft(), rectangle.topRight());
|
---|
1740 | if (node()->hasNodes() && nodeToGroupType()->isOpened())
|
---|
1741 | pPainter->drawLine(topRect.bottomLeft() + QPoint(iParentIndent, 0), topRect.bottomRight() + QPoint(1, 0));
|
---|
1742 | else
|
---|
1743 | pPainter->drawLine(topRect.bottomLeft(), topRect.bottomRight() + QPoint(1, 0));
|
---|
1744 | pPainter->drawLine(rectangle.topLeft(), rectangle.bottomLeft());
|
---|
1745 |
|
---|
1746 | /* Restore painter: */
|
---|
1747 | pPainter->restore();
|
---|
1748 | }
|
---|
1749 |
|
---|
1750 | void UIChooserItemGroup::paintHeader(QPainter *pPainter, const QRect &rect)
|
---|
1751 | {
|
---|
1752 | /* Not for root item: */
|
---|
1753 | if (isRoot())
|
---|
1754 | return;
|
---|
1755 |
|
---|
1756 | /* Prepare variables: */
|
---|
1757 | const int iMarginHL = data(GroupItemData_MarginHL).toInt();
|
---|
1758 | const int iMarginHR = data(GroupItemData_MarginHR).toInt();
|
---|
1759 | const int iMarginV = data(GroupItemData_MarginV).toInt();
|
---|
1760 | const int iHeaderSpacing = data(GroupItemData_HeaderSpacing).toInt();
|
---|
1761 | const int iFullHeaderHeight = m_minimumHeaderSize.height();
|
---|
1762 |
|
---|
1763 | /* Selected item foreground: */
|
---|
1764 | if (model()->selectedItems().contains(this))
|
---|
1765 | {
|
---|
1766 | /* Prepare palette: */
|
---|
1767 | const QPalette pal = QApplication::palette();
|
---|
1768 |
|
---|
1769 | /* Get background color: */
|
---|
1770 | const QColor background = pal.color(QPalette::Active, QPalette::Highlight).lighter(m_iHighlightLightness);
|
---|
1771 |
|
---|
1772 | /* Gather foreground color for background one: */
|
---|
1773 | const QColor foreground = suitableForegroundColor(pal, background);
|
---|
1774 | pPainter->setPen(foreground);
|
---|
1775 | }
|
---|
1776 |
|
---|
1777 | /* Paint name: */
|
---|
1778 | int iNameX = iMarginHL;
|
---|
1779 | if (!isRoot())
|
---|
1780 | iNameX += m_toggleButtonSize.width();
|
---|
1781 | iNameX += iHeaderSpacing;
|
---|
1782 | int iNameY = m_visibleNameSize.height() == iFullHeaderHeight ? iMarginV :
|
---|
1783 | iMarginV + (iFullHeaderHeight - m_visibleNameSize.height()) / 2;
|
---|
1784 | paintText(/* Painter: */
|
---|
1785 | pPainter,
|
---|
1786 | /* Point to paint in: */
|
---|
1787 | QPoint(iNameX, iNameY),
|
---|
1788 | /* Font to paint text: */
|
---|
1789 | m_nameFont,
|
---|
1790 | /* Paint device: */
|
---|
1791 | model()->paintDevice(),
|
---|
1792 | /* Text to paint: */
|
---|
1793 | m_strVisibleName);
|
---|
1794 |
|
---|
1795 | /* Should we add more info? */
|
---|
1796 | if (isHovered())
|
---|
1797 | {
|
---|
1798 | /* Indent: */
|
---|
1799 | int iHorizontalIndent = rect.right() - iMarginHR;
|
---|
1800 |
|
---|
1801 | /* Should we draw machine count info? */
|
---|
1802 | if (!m_strInfoMachines.isEmpty())
|
---|
1803 | {
|
---|
1804 | iHorizontalIndent -= m_infoSizeMachines.width();
|
---|
1805 | int iMachineCountTextX = iHorizontalIndent;
|
---|
1806 | int iMachineCountTextY = m_infoSizeMachines.height() == iFullHeaderHeight ?
|
---|
1807 | iMarginV : iMarginV + (iFullHeaderHeight - m_infoSizeMachines.height()) / 2;
|
---|
1808 | paintText(/* Painter: */
|
---|
1809 | pPainter,
|
---|
1810 | /* Point to paint in: */
|
---|
1811 | QPoint(iMachineCountTextX, iMachineCountTextY),
|
---|
1812 | /* Font to paint text: */
|
---|
1813 | m_infoFont,
|
---|
1814 | /* Paint device: */
|
---|
1815 | model()->paintDevice(),
|
---|
1816 | /* Text to paint: */
|
---|
1817 | m_strInfoMachines);
|
---|
1818 |
|
---|
1819 | iHorizontalIndent -= m_pixmapSizeMachines.width();
|
---|
1820 | int iMachinePixmapX = iHorizontalIndent;
|
---|
1821 | int iMachinePixmapY = m_pixmapSizeMachines.height() == iFullHeaderHeight ?
|
---|
1822 | iMarginV : iMarginV + (iFullHeaderHeight - m_pixmapSizeMachines.height()) / 2;
|
---|
1823 | paintPixmap(/* Painter: */
|
---|
1824 | pPainter,
|
---|
1825 | /* Point to paint in: */
|
---|
1826 | QPoint(iMachinePixmapX, iMachinePixmapY),
|
---|
1827 | /* Pixmap to paint: */
|
---|
1828 | m_machinesPixmap);
|
---|
1829 | }
|
---|
1830 |
|
---|
1831 | /* Should we draw group count info? */
|
---|
1832 | if (!m_strInfoGroups.isEmpty())
|
---|
1833 | {
|
---|
1834 | iHorizontalIndent -= m_infoSizeGroups.width();
|
---|
1835 | int iGroupCountTextX = iHorizontalIndent;
|
---|
1836 | int iGroupCountTextY = m_infoSizeGroups.height() == iFullHeaderHeight ?
|
---|
1837 | iMarginV : iMarginV + (iFullHeaderHeight - m_infoSizeGroups.height()) / 2;
|
---|
1838 | paintText(/* Painter: */
|
---|
1839 | pPainter,
|
---|
1840 | /* Point to paint in: */
|
---|
1841 | QPoint(iGroupCountTextX, iGroupCountTextY),
|
---|
1842 | /* Font to paint text: */
|
---|
1843 | m_infoFont,
|
---|
1844 | /* Paint device: */
|
---|
1845 | model()->paintDevice(),
|
---|
1846 | /* Text to paint: */
|
---|
1847 | m_strInfoGroups);
|
---|
1848 |
|
---|
1849 | iHorizontalIndent -= m_pixmapSizeGroups.width();
|
---|
1850 | int iGroupPixmapX = iHorizontalIndent;
|
---|
1851 | int iGroupPixmapY = m_pixmapSizeGroups.height() == iFullHeaderHeight ?
|
---|
1852 | iMarginV : iMarginV + (iFullHeaderHeight - m_pixmapSizeGroups.height()) / 2;
|
---|
1853 | paintPixmap(/* Painter: */
|
---|
1854 | pPainter,
|
---|
1855 | /* Point to paint in: */
|
---|
1856 | QPoint(iGroupPixmapX, iGroupPixmapY),
|
---|
1857 | /* Pixmap to paint: */
|
---|
1858 | m_groupsPixmap);
|
---|
1859 | }
|
---|
1860 | }
|
---|
1861 | }
|
---|
1862 |
|
---|
1863 |
|
---|
1864 | /*********************************************************************************************************************************
|
---|
1865 | * Class UIEditorGroupRename implementation. *
|
---|
1866 | *********************************************************************************************************************************/
|
---|
1867 |
|
---|
1868 | UIEditorGroupRename::UIEditorGroupRename(const QString &strName)
|
---|
1869 | : QWidget(0, Qt::Popup)
|
---|
1870 | , m_pLineEdit(0)
|
---|
1871 | {
|
---|
1872 | /* Create layout: */
|
---|
1873 | QHBoxLayout *pLayout = new QHBoxLayout(this);
|
---|
1874 | if (pLayout)
|
---|
1875 | {
|
---|
1876 | /* Configure layout: */
|
---|
1877 | pLayout->setContentsMargins(0, 0, 0, 0);
|
---|
1878 |
|
---|
1879 | /* Create line-edit: */
|
---|
1880 | m_pLineEdit = new QLineEdit(strName);
|
---|
1881 | if (m_pLineEdit)
|
---|
1882 | {
|
---|
1883 | setFocusProxy(m_pLineEdit);
|
---|
1884 | m_pLineEdit->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
---|
1885 | m_pLineEdit->setTextMargins(0, 0, 0, 0);
|
---|
1886 | connect(m_pLineEdit, &QLineEdit::returnPressed,
|
---|
1887 | this, &UIEditorGroupRename::sigEditingFinished);
|
---|
1888 | }
|
---|
1889 |
|
---|
1890 | /* Add into layout: */
|
---|
1891 | pLayout->addWidget(m_pLineEdit);
|
---|
1892 | }
|
---|
1893 | }
|
---|
1894 |
|
---|
1895 | QString UIEditorGroupRename::text() const
|
---|
1896 | {
|
---|
1897 | return m_pLineEdit->text();
|
---|
1898 | }
|
---|
1899 |
|
---|
1900 | void UIEditorGroupRename::setText(const QString &strText)
|
---|
1901 | {
|
---|
1902 | m_pLineEdit->setText(strText);
|
---|
1903 | }
|
---|
1904 |
|
---|
1905 | void UIEditorGroupRename::setFont(const QFont &font)
|
---|
1906 | {
|
---|
1907 | QWidget::setFont(font);
|
---|
1908 | m_pLineEdit->setFont(font);
|
---|
1909 | }
|
---|