source: trunk/tools/designer/src/lib/shared/formwindowbase.cpp@ 846

Last change on this file since 846 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 16.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the Qt Designer of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "formwindowbase_p.h"
43#include "connectionedit_p.h"
44#include "qdesigner_command_p.h"
45#include "qdesigner_propertysheet_p.h"
46#include "qdesigner_propertyeditor_p.h"
47#include "qdesigner_menu_p.h"
48#include "qdesigner_menubar_p.h"
49#include "shared_settings_p.h"
50#include "grid_p.h"
51#include "deviceprofile_p.h"
52#include "qdesigner_utils_p.h"
53
54#include "qsimpleresource_p.h"
55
56#include <QtDesigner/QDesignerFormEditorInterface>
57#include <QtDesigner/QDesignerContainerExtension>
58#include <QtDesigner/QExtensionManager>
59#include <QtDesigner/QDesignerTaskMenuExtension>
60
61#include <QtCore/qdebug.h>
62#include <QtCore/QList>
63#include <QtCore/QTimer>
64#include <QtGui/QMenu>
65#include <QtGui/QListWidget>
66#include <QtGui/QTreeWidget>
67#include <QtGui/QTableWidget>
68#include <QtGui/QComboBox>
69#include <QtGui/QTabWidget>
70#include <QtGui/QToolBox>
71#include <QtGui/QToolBar>
72#include <QtGui/QStatusBar>
73#include <QtGui/QMenu>
74#include <QtGui/QAction>
75#include <QtGui/QLabel>
76
77QT_BEGIN_NAMESPACE
78
79namespace qdesigner_internal {
80
81class FormWindowBasePrivate {
82public:
83 explicit FormWindowBasePrivate(QDesignerFormEditorInterface *core);
84
85 static Grid m_defaultGrid;
86
87 QDesignerFormWindowInterface::Feature m_feature;
88 Grid m_grid;
89 bool m_hasFormGrid;
90 DesignerPixmapCache *m_pixmapCache;
91 DesignerIconCache *m_iconCache;
92 QtResourceSet *m_resourceSet;
93 QMap<QDesignerPropertySheet *, QMap<int, bool> > m_reloadableResources; // bool is dummy, QMap used as QSet
94 QMap<QDesignerPropertySheet *, QObject *> m_reloadablePropertySheets;
95 const DeviceProfile m_deviceProfile;
96 FormWindowBase::LineTerminatorMode m_lineTerminatorMode;
97 FormWindowBase::SaveResourcesBehaviour m_saveResourcesBehaviour;
98};
99
100FormWindowBasePrivate::FormWindowBasePrivate(QDesignerFormEditorInterface *core) :
101 m_feature(QDesignerFormWindowInterface::DefaultFeature),
102 m_grid(m_defaultGrid),
103 m_hasFormGrid(false),
104 m_pixmapCache(0),
105 m_iconCache(0),
106 m_resourceSet(0),
107 m_deviceProfile(QDesignerSharedSettings(core).currentDeviceProfile()),
108 m_lineTerminatorMode(FormWindowBase::NativeLineTerminator),
109 m_saveResourcesBehaviour(FormWindowBase::SaveAll)
110{
111}
112
113Grid FormWindowBasePrivate::m_defaultGrid;
114
115FormWindowBase::FormWindowBase(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) :
116 QDesignerFormWindowInterface(parent, flags),
117 m_d(new FormWindowBasePrivate(core))
118{
119 syncGridFeature();
120 m_d->m_pixmapCache = new DesignerPixmapCache(this);
121 m_d->m_iconCache = new DesignerIconCache(m_d->m_pixmapCache, this);
122}
123
124FormWindowBase::~FormWindowBase()
125{
126 delete m_d;
127}
128
129DesignerPixmapCache *FormWindowBase::pixmapCache() const
130{
131 return m_d->m_pixmapCache;
132}
133
134DesignerIconCache *FormWindowBase::iconCache() const
135{
136 return m_d->m_iconCache;
137}
138
139QtResourceSet *FormWindowBase::resourceSet() const
140{
141 return m_d->m_resourceSet;
142}
143
144void FormWindowBase::setResourceSet(QtResourceSet *resourceSet)
145{
146 m_d->m_resourceSet = resourceSet;
147}
148
149void FormWindowBase::addReloadableProperty(QDesignerPropertySheet *sheet, int index)
150{
151 m_d->m_reloadableResources[sheet][index] = true;
152}
153
154void FormWindowBase::removeReloadableProperty(QDesignerPropertySheet *sheet, int index)
155{
156 m_d->m_reloadableResources[sheet].remove(index);
157 if (m_d->m_reloadableResources[sheet].count() == 0)
158 m_d->m_reloadableResources.remove(sheet);
159}
160
161void FormWindowBase::addReloadablePropertySheet(QDesignerPropertySheet *sheet, QObject *object)
162{
163 if (qobject_cast<QTreeWidget *>(object) ||
164 qobject_cast<QTableWidget *>(object) ||
165 qobject_cast<QListWidget *>(object) ||
166 qobject_cast<QComboBox *>(object))
167 m_d->m_reloadablePropertySheets[sheet] = object;
168}
169
170void FormWindowBase::removeReloadablePropertySheet(QDesignerPropertySheet *sheet)
171{
172 m_d->m_reloadablePropertySheets.remove(sheet);
173}
174
175void FormWindowBase::reloadProperties()
176{
177 pixmapCache()->clear();
178 iconCache()->clear();
179 QMapIterator<QDesignerPropertySheet *, QMap<int, bool> > itSheet(m_d->m_reloadableResources);
180 while (itSheet.hasNext()) {
181 QDesignerPropertySheet *sheet = itSheet.next().key();
182 QMapIterator<int, bool> itIndex(itSheet.value());
183 while (itIndex.hasNext()) {
184 const int index = itIndex.next().key();
185 const QVariant newValue = sheet->property(index);
186 if (qobject_cast<QLabel *>(sheet->object()) && sheet->propertyName(index) == QLatin1String("text")) {
187 const PropertySheetStringValue newString = qVariantValue<PropertySheetStringValue>(newValue);
188 // optimize a bit, reset only if the text value might contain a reference to qt resources
189 // (however reloading of icons other than taken from resources might not work here)
190 if (newString.value().contains(QLatin1String(":/"))) {
191 const QVariant resetValue = qVariantFromValue(PropertySheetStringValue());
192 sheet->setProperty(index, resetValue);
193 }
194 }
195 sheet->setProperty(index, newValue);
196 }
197 if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(sheet->object())) {
198 const int count = tabWidget->count();
199 const int current = tabWidget->currentIndex();
200 const QString currentTabIcon = QLatin1String("currentTabIcon");
201 for (int i = 0; i < count; i++) {
202 tabWidget->setCurrentIndex(i);
203 const int index = sheet->indexOf(currentTabIcon);
204 sheet->setProperty(index, sheet->property(index));
205 }
206 tabWidget->setCurrentIndex(current);
207 } else if (QToolBox *toolBox = qobject_cast<QToolBox *>(sheet->object())) {
208 const int count = toolBox->count();
209 const int current = toolBox->currentIndex();
210 const QString currentItemIcon = QLatin1String("currentItemIcon");
211 for (int i = 0; i < count; i++) {
212 toolBox->setCurrentIndex(i);
213 const int index = sheet->indexOf(currentItemIcon);
214 sheet->setProperty(index, sheet->property(index));
215 }
216 toolBox->setCurrentIndex(current);
217 }
218 }
219 QMapIterator<QDesignerPropertySheet *, QObject *> itSh(m_d->m_reloadablePropertySheets);
220 while (itSh.hasNext()) {
221 QObject *object = itSh.next().value();
222 reloadIconResources(iconCache(), object);
223 }
224}
225
226void FormWindowBase::resourceSetActivated(QtResourceSet *resource, bool resourceSetChanged)
227{
228 if (resource == resourceSet() && resourceSetChanged) {
229 reloadProperties();
230 emit pixmapCache()->reloaded();
231 emit iconCache()->reloaded();
232 if (QDesignerPropertyEditor *propertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor()))
233 propertyEditor->reloadResourceProperties();
234 }
235}
236
237QVariantMap FormWindowBase::formData()
238{
239 QVariantMap rc;
240 if (m_d->m_hasFormGrid)
241 m_d->m_grid.addToVariantMap(rc, true);
242 return rc;
243}
244
245void FormWindowBase::setFormData(const QVariantMap &vm)
246{
247 Grid formGrid;
248 m_d->m_hasFormGrid = formGrid.fromVariantMap(vm);
249 if (m_d->m_hasFormGrid)
250 m_d->m_grid = formGrid;
251}
252
253QPoint FormWindowBase::grid() const
254{
255 return QPoint(m_d->m_grid.deltaX(), m_d->m_grid.deltaY());
256}
257
258void FormWindowBase::setGrid(const QPoint &grid)
259{
260 m_d->m_grid.setDeltaX(grid.x());
261 m_d->m_grid.setDeltaY(grid.y());
262}
263
264bool FormWindowBase::hasFeature(Feature f) const
265{
266 return f & m_d->m_feature;
267}
268
269static void recursiveUpdate(QWidget *w)
270{
271 w->update();
272
273 const QObjectList &l = w->children();
274 const QObjectList::const_iterator cend = l.constEnd();
275 for (QObjectList::const_iterator it = l.constBegin(); it != cend; ++it) {
276 if (QWidget *w = qobject_cast<QWidget*>(*it))
277 recursiveUpdate(w);
278 }
279}
280
281void FormWindowBase::setFeatures(Feature f)
282{
283 m_d->m_feature = f;
284 const bool enableGrid = f & GridFeature;
285 m_d->m_grid.setVisible(enableGrid);
286 m_d->m_grid.setSnapX(enableGrid);
287 m_d->m_grid.setSnapY(enableGrid);
288 emit featureChanged(f);
289 recursiveUpdate(this);
290}
291
292FormWindowBase::Feature FormWindowBase::features() const
293{
294 return m_d->m_feature;
295}
296
297bool FormWindowBase::gridVisible() const
298{
299 return m_d->m_grid.visible() && currentTool() == 0;
300}
301
302FormWindowBase::SaveResourcesBehaviour FormWindowBase::saveResourcesBehaviour() const
303{
304 return m_d->m_saveResourcesBehaviour;
305}
306
307void FormWindowBase::setSaveResourcesBehaviour(SaveResourcesBehaviour behaviour)
308{
309 m_d->m_saveResourcesBehaviour = behaviour;
310}
311
312void FormWindowBase::syncGridFeature()
313{
314 if (m_d->m_grid.snapX() || m_d->m_grid.snapY())
315 m_d->m_feature |= GridFeature;
316 else
317 m_d->m_feature &= ~GridFeature;
318}
319
320void FormWindowBase::setDesignerGrid(const Grid& grid)
321{
322 m_d->m_grid = grid;
323 syncGridFeature();
324 recursiveUpdate(this);
325}
326
327const Grid &FormWindowBase::designerGrid() const
328{
329 return m_d->m_grid;
330}
331
332bool FormWindowBase::hasFormGrid() const
333{
334 return m_d->m_hasFormGrid;
335}
336
337void FormWindowBase::setHasFormGrid(bool b)
338{
339 m_d->m_hasFormGrid = b;
340}
341
342void FormWindowBase::setDefaultDesignerGrid(const Grid& grid)
343{
344 FormWindowBasePrivate::m_defaultGrid = grid;
345}
346
347const Grid &FormWindowBase::defaultDesignerGrid()
348{
349 return FormWindowBasePrivate::m_defaultGrid;
350}
351
352QMenu *FormWindowBase::initializePopupMenu(QWidget * /*managedWidget*/)
353{
354 return 0;
355}
356
357// Widget under mouse for finding the Widget to highlight
358// when doing DnD. Restricts to pages by geometry if a container with
359// a container extension (or one of its helper widgets) is hit; otherwise
360// returns the widget as such (be it managed/unmanaged)
361
362QWidget *FormWindowBase::widgetUnderMouse(const QPoint &formPos, WidgetUnderMouseMode /* wum */)
363{
364 // widget_under_mouse might be some temporary thing like the dropLine. We need
365 // the actual widget that's part of the edited GUI.
366 QWidget *rc = widgetAt(formPos);
367 if (!rc || qobject_cast<ConnectionEdit*>(rc))
368 return 0;
369
370 if (rc == mainContainer()) {
371 // Refuse main container areas if the main container has a container extension,
372 // for example when hitting QToolBox/QTabWidget empty areas.
373 if (qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), rc))
374 return 0;
375 return rc;
376 }
377
378 // If we hit on container extension type container, make sure
379 // we use the top-most current page
380 if (QWidget *container = findContainer(rc, false))
381 if (QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), container)) {
382 // For container that do not have a "stacked" nature (QToolBox, QMdiArea),
383 // make sure the position is within the current page
384 const int ci = c->currentIndex();
385 if (ci < 0)
386 return 0;
387 QWidget *page = c->widget(ci);
388 QRect pageGeometry = page->geometry();
389 pageGeometry.moveTo(page->mapTo(this, pageGeometry.topLeft()));
390 if (!pageGeometry.contains(formPos))
391 return 0;
392 return page;
393 }
394
395 return rc;
396}
397
398void FormWindowBase::deleteWidgetList(const QWidgetList &widget_list)
399{
400 // We need a macro here even for single widgets because the some components (for example,
401 // the signal slot editor are connected to widgetRemoved() and add their
402 // own commands (for example, to delete w's connections)
403 const QString description = widget_list.size() == 1 ?
404 tr("Delete '%1'").arg(widget_list.front()->objectName()) : tr("Delete");
405
406 commandHistory()->beginMacro(description);
407 foreach (QWidget *w, widget_list) {
408 emit widgetRemoved(w);
409 DeleteWidgetCommand *cmd = new DeleteWidgetCommand(this);
410 cmd->init(w);
411 commandHistory()->push(cmd);
412 }
413 commandHistory()->endMacro();
414}
415
416QMenu *FormWindowBase::createExtensionTaskMenu(QDesignerFormWindowInterface *fw, QObject *o, bool trailingSeparator)
417{
418 typedef QList<QAction *> ActionList;
419 ActionList actions;
420 // 1) Standard public extension
421 QExtensionManager *em = fw->core()->extensionManager();
422 if (const QDesignerTaskMenuExtension *extTaskMenu = qt_extension<QDesignerTaskMenuExtension*>(em, o))
423 actions += extTaskMenu->taskActions();
424 if (const QDesignerTaskMenuExtension *intTaskMenu = qobject_cast<QDesignerTaskMenuExtension *>(em->extension(o, QLatin1String("QDesignerInternalTaskMenuExtension")))) {
425 if (!actions.empty()) {
426 QAction *a = new QAction(fw);
427 a->setSeparator(true);
428 actions.push_back(a);
429 }
430 actions += intTaskMenu->taskActions();
431 }
432 if (actions.empty())
433 return 0;
434 if (trailingSeparator && !actions.back()->isSeparator()) {
435 QAction *a = new QAction(fw);
436 a->setSeparator(true);
437 actions.push_back(a);
438 }
439 QMenu *rc = new QMenu;
440 const ActionList::const_iterator cend = actions.constEnd();
441 for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it)
442 rc->addAction(*it);
443 return rc;
444}
445
446void FormWindowBase::emitObjectRemoved(QObject *o)
447{
448 emit objectRemoved(o);
449}
450
451DeviceProfile FormWindowBase::deviceProfile() const
452{
453 return m_d->m_deviceProfile;
454}
455
456QString FormWindowBase::styleName() const
457{
458 return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.style();
459}
460
461void FormWindowBase::emitWidgetRemoved(QWidget *w)
462{
463 emit widgetRemoved(w);
464}
465
466QString FormWindowBase::deviceProfileName() const
467{
468 return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.name();
469}
470
471void FormWindowBase::setLineTerminatorMode(FormWindowBase::LineTerminatorMode mode)
472{
473 m_d->m_lineTerminatorMode = mode;
474}
475
476FormWindowBase::LineTerminatorMode FormWindowBase::lineTerminatorMode() const
477{
478 return m_d->m_lineTerminatorMode;
479}
480
481void FormWindowBase::triggerDefaultAction(QWidget *widget)
482{
483 if (QAction *action = qdesigner_internal::preferredEditAction(core(), widget))
484 QTimer::singleShot(0, action, SIGNAL(triggered()));
485}
486
487void FormWindowBase::setupDefaultAction(QDesignerFormWindowInterface *fw)
488{
489 QObject::connect(fw, SIGNAL(activated(QWidget*)), fw, SLOT(triggerDefaultAction(QWidget*)));
490}
491
492QString FormWindowBase::fileContents() const
493{
494 const bool oldValue = QSimpleResource::setWarningsEnabled(false);
495 const QString rc = contents();
496 QSimpleResource::setWarningsEnabled(oldValue);
497 return rc;
498}
499
500} // namespace qdesigner_internal
501
502QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.