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

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

trunk: Merged in qt 4.6.2 sources.

File size: 15.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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
76QT_BEGIN_NAMESPACE
77
78namespace qdesigner_internal {
79
80class FormWindowBasePrivate {
81public:
82 explicit FormWindowBasePrivate(QDesignerFormEditorInterface *core);
83
84 static Grid m_defaultGrid;
85
86 QDesignerFormWindowInterface::Feature m_feature;
87 Grid m_grid;
88 bool m_hasFormGrid;
89 DesignerPixmapCache *m_pixmapCache;
90 DesignerIconCache *m_iconCache;
91 QtResourceSet *m_resourceSet;
92 QMap<QDesignerPropertySheet *, QMap<int, bool> > m_reloadableResources; // bool is dummy, QMap used as QSet
93 QMap<QDesignerPropertySheet *, QObject *> m_reloadablePropertySheets;
94 const DeviceProfile m_deviceProfile;
95 FormWindowBase::LineTerminatorMode m_lineTerminatorMode;
96 FormWindowBase::SaveResourcesBehaviour m_saveResourcesBehaviour;
97};
98
99FormWindowBasePrivate::FormWindowBasePrivate(QDesignerFormEditorInterface *core) :
100 m_feature(QDesignerFormWindowInterface::DefaultFeature),
101 m_grid(m_defaultGrid),
102 m_hasFormGrid(false),
103 m_pixmapCache(0),
104 m_iconCache(0),
105 m_resourceSet(0),
106 m_deviceProfile(QDesignerSharedSettings(core).currentDeviceProfile()),
107 m_lineTerminatorMode(FormWindowBase::NativeLineTerminator),
108 m_saveResourcesBehaviour(FormWindowBase::SaveAll)
109{
110}
111
112Grid FormWindowBasePrivate::m_defaultGrid;
113
114FormWindowBase::FormWindowBase(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) :
115 QDesignerFormWindowInterface(parent, flags),
116 m_d(new FormWindowBasePrivate(core))
117{
118 syncGridFeature();
119 m_d->m_pixmapCache = new DesignerPixmapCache(this);
120 m_d->m_iconCache = new DesignerIconCache(m_d->m_pixmapCache, this);
121}
122
123FormWindowBase::~FormWindowBase()
124{
125 delete m_d;
126}
127
128DesignerPixmapCache *FormWindowBase::pixmapCache() const
129{
130 return m_d->m_pixmapCache;
131}
132
133DesignerIconCache *FormWindowBase::iconCache() const
134{
135 return m_d->m_iconCache;
136}
137
138QtResourceSet *FormWindowBase::resourceSet() const
139{
140 return m_d->m_resourceSet;
141}
142
143void FormWindowBase::setResourceSet(QtResourceSet *resourceSet)
144{
145 m_d->m_resourceSet = resourceSet;
146}
147
148void FormWindowBase::addReloadableProperty(QDesignerPropertySheet *sheet, int index)
149{
150 m_d->m_reloadableResources[sheet][index] = true;
151}
152
153void FormWindowBase::removeReloadableProperty(QDesignerPropertySheet *sheet, int index)
154{
155 m_d->m_reloadableResources[sheet].remove(index);
156 if (m_d->m_reloadableResources[sheet].count() == 0)
157 m_d->m_reloadableResources.remove(sheet);
158}
159
160void FormWindowBase::addReloadablePropertySheet(QDesignerPropertySheet *sheet, QObject *object)
161{
162 if (qobject_cast<QTreeWidget *>(object) ||
163 qobject_cast<QTableWidget *>(object) ||
164 qobject_cast<QListWidget *>(object) ||
165 qobject_cast<QComboBox *>(object))
166 m_d->m_reloadablePropertySheets[sheet] = object;
167}
168
169void FormWindowBase::removeReloadablePropertySheet(QDesignerPropertySheet *sheet)
170{
171 m_d->m_reloadablePropertySheets.remove(sheet);
172}
173
174void FormWindowBase::reloadProperties()
175{
176 pixmapCache()->clear();
177 iconCache()->clear();
178 QMapIterator<QDesignerPropertySheet *, QMap<int, bool> > itSheet(m_d->m_reloadableResources);
179 while (itSheet.hasNext()) {
180 QDesignerPropertySheet *sheet = itSheet.next().key();
181 QMapIterator<int, bool> itIndex(itSheet.value());
182 while (itIndex.hasNext()) {
183 const int index = itIndex.next().key();
184 sheet->setProperty(index, sheet->property(index));
185 }
186 if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(sheet->object())) {
187 const int count = tabWidget->count();
188 const int current = tabWidget->currentIndex();
189 const QString currentTabIcon = QLatin1String("currentTabIcon");
190 for (int i = 0; i < count; i++) {
191 tabWidget->setCurrentIndex(i);
192 const int index = sheet->indexOf(currentTabIcon);
193 sheet->setProperty(index, sheet->property(index));
194 }
195 tabWidget->setCurrentIndex(current);
196 } else if (QToolBox *toolBox = qobject_cast<QToolBox *>(sheet->object())) {
197 const int count = toolBox->count();
198 const int current = toolBox->currentIndex();
199 const QString currentItemIcon = QLatin1String("currentItemIcon");
200 for (int i = 0; i < count; i++) {
201 toolBox->setCurrentIndex(i);
202 const int index = sheet->indexOf(currentItemIcon);
203 sheet->setProperty(index, sheet->property(index));
204 }
205 toolBox->setCurrentIndex(current);
206 }
207 }
208 QMapIterator<QDesignerPropertySheet *, QObject *> itSh(m_d->m_reloadablePropertySheets);
209 while (itSh.hasNext()) {
210 QObject *object = itSh.next().value();
211 reloadIconResources(iconCache(), object);
212 }
213}
214
215void FormWindowBase::resourceSetActivated(QtResourceSet *resource, bool resourceSetChanged)
216{
217 if (resource == resourceSet() && resourceSetChanged) {
218 reloadProperties();
219 emit pixmapCache()->reloaded();
220 emit iconCache()->reloaded();
221 if (QDesignerPropertyEditor *propertyEditor = qobject_cast<QDesignerPropertyEditor *>(core()->propertyEditor()))
222 propertyEditor->reloadResourceProperties();
223 }
224}
225
226QVariantMap FormWindowBase::formData()
227{
228 QVariantMap rc;
229 if (m_d->m_hasFormGrid)
230 m_d->m_grid.addToVariantMap(rc, true);
231 return rc;
232}
233
234void FormWindowBase::setFormData(const QVariantMap &vm)
235{
236 Grid formGrid;
237 m_d->m_hasFormGrid = formGrid.fromVariantMap(vm);
238 if (m_d->m_hasFormGrid)
239 m_d->m_grid = formGrid;
240}
241
242QPoint FormWindowBase::grid() const
243{
244 return QPoint(m_d->m_grid.deltaX(), m_d->m_grid.deltaY());
245}
246
247void FormWindowBase::setGrid(const QPoint &grid)
248{
249 m_d->m_grid.setDeltaX(grid.x());
250 m_d->m_grid.setDeltaY(grid.y());
251}
252
253bool FormWindowBase::hasFeature(Feature f) const
254{
255 return f & m_d->m_feature;
256}
257
258static void recursiveUpdate(QWidget *w)
259{
260 w->update();
261
262 const QObjectList &l = w->children();
263 const QObjectList::const_iterator cend = l.constEnd();
264 for (QObjectList::const_iterator it = l.constBegin(); it != cend; ++it) {
265 if (QWidget *w = qobject_cast<QWidget*>(*it))
266 recursiveUpdate(w);
267 }
268}
269
270void FormWindowBase::setFeatures(Feature f)
271{
272 m_d->m_feature = f;
273 const bool enableGrid = f & GridFeature;
274 m_d->m_grid.setVisible(enableGrid);
275 m_d->m_grid.setSnapX(enableGrid);
276 m_d->m_grid.setSnapY(enableGrid);
277 emit featureChanged(f);
278 recursiveUpdate(this);
279}
280
281FormWindowBase::Feature FormWindowBase::features() const
282{
283 return m_d->m_feature;
284}
285
286bool FormWindowBase::gridVisible() const
287{
288 return m_d->m_grid.visible() && currentTool() == 0;
289}
290
291FormWindowBase::SaveResourcesBehaviour FormWindowBase::saveResourcesBehaviour() const
292{
293 return m_d->m_saveResourcesBehaviour;
294}
295
296void FormWindowBase::setSaveResourcesBehaviour(SaveResourcesBehaviour behaviour)
297{
298 m_d->m_saveResourcesBehaviour = behaviour;
299}
300
301void FormWindowBase::syncGridFeature()
302{
303 if (m_d->m_grid.snapX() || m_d->m_grid.snapY())
304 m_d->m_feature |= GridFeature;
305 else
306 m_d->m_feature &= ~GridFeature;
307}
308
309void FormWindowBase::setDesignerGrid(const Grid& grid)
310{
311 m_d->m_grid = grid;
312 syncGridFeature();
313 recursiveUpdate(this);
314}
315
316const Grid &FormWindowBase::designerGrid() const
317{
318 return m_d->m_grid;
319}
320
321bool FormWindowBase::hasFormGrid() const
322{
323 return m_d->m_hasFormGrid;
324}
325
326void FormWindowBase::setHasFormGrid(bool b)
327{
328 m_d->m_hasFormGrid = b;
329}
330
331void FormWindowBase::setDefaultDesignerGrid(const Grid& grid)
332{
333 FormWindowBasePrivate::m_defaultGrid = grid;
334}
335
336const Grid &FormWindowBase::defaultDesignerGrid()
337{
338 return FormWindowBasePrivate::m_defaultGrid;
339}
340
341QMenu *FormWindowBase::initializePopupMenu(QWidget * /*managedWidget*/)
342{
343 return 0;
344}
345
346// Widget under mouse for finding the Widget to highlight
347// when doing DnD. Restricts to pages by geometry if a container with
348// a container extension (or one of its helper widgets) is hit; otherwise
349// returns the widget as such (be it managed/unmanaged)
350
351QWidget *FormWindowBase::widgetUnderMouse(const QPoint &formPos, WidgetUnderMouseMode /* wum */)
352{
353 // widget_under_mouse might be some temporary thing like the dropLine. We need
354 // the actual widget that's part of the edited GUI.
355 QWidget *rc = widgetAt(formPos);
356 if (!rc || qobject_cast<ConnectionEdit*>(rc))
357 return 0;
358
359 if (rc == mainContainer()) {
360 // Refuse main container areas if the main container has a container extension,
361 // for example when hitting QToolBox/QTabWidget empty areas.
362 if (qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), rc))
363 return 0;
364 return rc;
365 }
366
367 // If we hit on container extension type container, make sure
368 // we use the top-most current page
369 if (QWidget *container = findContainer(rc, false))
370 if (QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(core()->extensionManager(), container)) {
371 // For container that do not have a "stacked" nature (QToolBox, QMdiArea),
372 // make sure the position is within the current page
373 const int ci = c->currentIndex();
374 if (ci < 0)
375 return 0;
376 QWidget *page = c->widget(ci);
377 QRect pageGeometry = page->geometry();
378 pageGeometry.moveTo(page->mapTo(this, pageGeometry.topLeft()));
379 if (!pageGeometry.contains(formPos))
380 return 0;
381 return page;
382 }
383
384 return rc;
385}
386
387void FormWindowBase::deleteWidgetList(const QWidgetList &widget_list)
388{
389 // We need a macro here even for single widgets because the some components (for example,
390 // the signal slot editor are connected to widgetRemoved() and add their
391 // own commands (for example, to delete w's connections)
392 const QString description = widget_list.size() == 1 ?
393 tr("Delete '%1'").arg(widget_list.front()->objectName()) : tr("Delete");
394
395 commandHistory()->beginMacro(description);
396 foreach (QWidget *w, widget_list) {
397 emit widgetRemoved(w);
398 DeleteWidgetCommand *cmd = new DeleteWidgetCommand(this);
399 cmd->init(w);
400 commandHistory()->push(cmd);
401 }
402 commandHistory()->endMacro();
403}
404
405QMenu *FormWindowBase::createExtensionTaskMenu(QDesignerFormWindowInterface *fw, QObject *o, bool trailingSeparator)
406{
407 typedef QList<QAction *> ActionList;
408 ActionList actions;
409 // 1) Standard public extension
410 QExtensionManager *em = fw->core()->extensionManager();
411 if (const QDesignerTaskMenuExtension *extTaskMenu = qt_extension<QDesignerTaskMenuExtension*>(em, o))
412 actions += extTaskMenu->taskActions();
413 if (const QDesignerTaskMenuExtension *intTaskMenu = qobject_cast<QDesignerTaskMenuExtension *>(em->extension(o, QLatin1String("QDesignerInternalTaskMenuExtension")))) {
414 if (!actions.empty()) {
415 QAction *a = new QAction(fw);
416 a->setSeparator(true);
417 actions.push_back(a);
418 }
419 actions += intTaskMenu->taskActions();
420 }
421 if (actions.empty())
422 return 0;
423 if (trailingSeparator && !actions.back()->isSeparator()) {
424 QAction *a = new QAction(fw);
425 a->setSeparator(true);
426 actions.push_back(a);
427 }
428 QMenu *rc = new QMenu;
429 const ActionList::const_iterator cend = actions.constEnd();
430 for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it)
431 rc->addAction(*it);
432 return rc;
433}
434
435void FormWindowBase::emitObjectRemoved(QObject *o)
436{
437 emit objectRemoved(o);
438}
439
440DeviceProfile FormWindowBase::deviceProfile() const
441{
442 return m_d->m_deviceProfile;
443}
444
445QString FormWindowBase::styleName() const
446{
447 return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.style();
448}
449
450void FormWindowBase::emitWidgetRemoved(QWidget *w)
451{
452 emit widgetRemoved(w);
453}
454
455QString FormWindowBase::deviceProfileName() const
456{
457 return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.name();
458}
459
460void FormWindowBase::setLineTerminatorMode(FormWindowBase::LineTerminatorMode mode)
461{
462 m_d->m_lineTerminatorMode = mode;
463}
464
465FormWindowBase::LineTerminatorMode FormWindowBase::lineTerminatorMode() const
466{
467 return m_d->m_lineTerminatorMode;
468}
469
470void FormWindowBase::triggerDefaultAction(QWidget *widget)
471{
472 if (QAction *action = qdesigner_internal::preferredEditAction(core(), widget))
473 QTimer::singleShot(0, action, SIGNAL(triggered()));
474}
475
476void FormWindowBase::setupDefaultAction(QDesignerFormWindowInterface *fw)
477{
478 QObject::connect(fw, SIGNAL(activated(QWidget*)), fw, SLOT(triggerDefaultAction(QWidget*)));
479}
480
481QString FormWindowBase::fileContents() const
482{
483 const bool oldValue = QSimpleResource::setWarningsEnabled(false);
484 const QString rc = contents();
485 QSimpleResource::setWarningsEnabled(oldValue);
486 return rc;
487}
488
489} // namespace qdesigner_internal
490
491QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.