1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the Qt Designer of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** 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 are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include "promotiontaskmenu_p.h"
|
---|
43 | #include "qdesigner_promotiondialog_p.h"
|
---|
44 | #include "widgetfactory_p.h"
|
---|
45 | #include "metadatabase_p.h"
|
---|
46 | #include "widgetdatabase_p.h"
|
---|
47 | #include "qdesigner_command_p.h"
|
---|
48 | #include "signalslotdialog_p.h"
|
---|
49 | #include "qdesigner_objectinspector_p.h"
|
---|
50 | #include "abstractintrospection_p.h"
|
---|
51 |
|
---|
52 | #include <QtDesigner/QDesignerFormWindowInterface>
|
---|
53 | #include <QtDesigner/QDesignerFormWindowCursorInterface>
|
---|
54 | #include <QtDesigner/QDesignerLanguageExtension>
|
---|
55 | #include <QtDesigner/QDesignerFormEditorInterface>
|
---|
56 | #include <QtDesigner/QExtensionManager>
|
---|
57 |
|
---|
58 | #include <QtGui/QAction>
|
---|
59 | #include <QtGui/QWidget>
|
---|
60 | #include <QtGui/QMenu>
|
---|
61 | #include <QtCore/QSignalMapper>
|
---|
62 | #include <QtCore/qdebug.h>
|
---|
63 |
|
---|
64 | QT_BEGIN_NAMESPACE
|
---|
65 |
|
---|
66 | static QAction *separatorAction(QObject *parent)
|
---|
67 | {
|
---|
68 | QAction *rc = new QAction(parent);
|
---|
69 | rc->setSeparator(true);
|
---|
70 | return rc;
|
---|
71 | }
|
---|
72 |
|
---|
73 | static inline QDesignerLanguageExtension *languageExtension(QDesignerFormEditorInterface *core)
|
---|
74 | {
|
---|
75 | return qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core);
|
---|
76 | }
|
---|
77 |
|
---|
78 | namespace qdesigner_internal {
|
---|
79 |
|
---|
80 | PromotionTaskMenu::PromotionTaskMenu(QWidget *widget,Mode mode, QObject *parent) :
|
---|
81 | QObject(parent),
|
---|
82 | m_mode(mode),
|
---|
83 | m_widget(widget),
|
---|
84 | m_promotionMapper(0),
|
---|
85 | m_globalEditAction(new QAction(tr("Promoted widgets..."), this)),
|
---|
86 | m_EditPromoteToAction(new QAction(tr("Promote to ..."), this)),
|
---|
87 | m_EditSignalsSlotsAction(new QAction(tr("Change signals/slots..."), this)),
|
---|
88 | m_promoteLabel(tr("Promote to")),
|
---|
89 | m_demoteLabel(tr("Demote to %1"))
|
---|
90 | {
|
---|
91 | connect(m_globalEditAction, SIGNAL(triggered()), this, SLOT(slotEditPromotedWidgets()));
|
---|
92 | connect(m_EditPromoteToAction, SIGNAL(triggered()), this, SLOT(slotEditPromoteTo()));
|
---|
93 | connect(m_EditSignalsSlotsAction, SIGNAL(triggered()), this, SLOT(slotEditSignalsSlots()));
|
---|
94 | }
|
---|
95 |
|
---|
96 | PromotionTaskMenu::Mode PromotionTaskMenu::mode() const
|
---|
97 | {
|
---|
98 | return m_mode;
|
---|
99 | }
|
---|
100 |
|
---|
101 | void PromotionTaskMenu::setMode(Mode m)
|
---|
102 | {
|
---|
103 | m_mode = m;
|
---|
104 | }
|
---|
105 |
|
---|
106 | void PromotionTaskMenu::setWidget(QWidget *widget)
|
---|
107 | {
|
---|
108 | m_widget = widget;
|
---|
109 | }
|
---|
110 |
|
---|
111 | void PromotionTaskMenu::setPromoteLabel(const QString &promoteLabel)
|
---|
112 | {
|
---|
113 | m_promoteLabel = promoteLabel;
|
---|
114 | }
|
---|
115 |
|
---|
116 | void PromotionTaskMenu::setEditPromoteToLabel(const QString &promoteEditLabel)
|
---|
117 | {
|
---|
118 | m_EditPromoteToAction->setText(promoteEditLabel);
|
---|
119 | }
|
---|
120 |
|
---|
121 | void PromotionTaskMenu::setDemoteLabel(const QString &demoteLabel)
|
---|
122 | {
|
---|
123 | m_demoteLabel = demoteLabel;
|
---|
124 | }
|
---|
125 |
|
---|
126 | PromotionTaskMenu::PromotionState PromotionTaskMenu::createPromotionActions(QDesignerFormWindowInterface *formWindow)
|
---|
127 | {
|
---|
128 | // clear out old
|
---|
129 | if (!m_promotionActions.empty()) {
|
---|
130 | qDeleteAll(m_promotionActions);
|
---|
131 | m_promotionActions.clear();
|
---|
132 | }
|
---|
133 | // No promotion of main container
|
---|
134 | if (formWindow->mainContainer() == m_widget)
|
---|
135 | return NotApplicable;
|
---|
136 |
|
---|
137 | // Check for a homogenous selection
|
---|
138 | const PromotionSelectionList promotionSelection = promotionSelectionList(formWindow);
|
---|
139 |
|
---|
140 | if (promotionSelection.empty())
|
---|
141 | return NoHomogenousSelection;
|
---|
142 |
|
---|
143 | QDesignerFormEditorInterface *core = formWindow->core();
|
---|
144 | // if it is promoted: demote only.
|
---|
145 | if (isPromoted(formWindow->core(), m_widget)) {
|
---|
146 | const QString label = m_demoteLabel.arg( promotedExtends(core , m_widget));
|
---|
147 | QAction *demoteAction = new QAction(label, this);
|
---|
148 | connect(demoteAction, SIGNAL(triggered()), this, SLOT(slotDemoteFromCustomWidget()));
|
---|
149 | m_promotionActions.push_back(demoteAction);
|
---|
150 | return CanDemote;
|
---|
151 | }
|
---|
152 | // figure out candidates
|
---|
153 | const QString baseClassName = WidgetFactory::classNameOf(core, m_widget);
|
---|
154 | const WidgetDataBaseItemList candidates = promotionCandidates(core->widgetDataBase(), baseClassName );
|
---|
155 | if (candidates.empty()) {
|
---|
156 | // Is this thing promotable at all?
|
---|
157 | return QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(baseClassName) ? CanPromote : NotApplicable;
|
---|
158 | }
|
---|
159 | // Set up a signal mapper to associate class names
|
---|
160 | if (!m_promotionMapper) {
|
---|
161 | m_promotionMapper = new QSignalMapper(this);
|
---|
162 | connect(m_promotionMapper, SIGNAL(mapped(QString)), this, SLOT(slotPromoteToCustomWidget(QString)));
|
---|
163 | }
|
---|
164 |
|
---|
165 | QMenu *candidatesMenu = new QMenu();
|
---|
166 | // Create a sub menu
|
---|
167 | const WidgetDataBaseItemList::const_iterator cend = candidates.constEnd();
|
---|
168 | // Set up actions and map class names
|
---|
169 | for (WidgetDataBaseItemList::const_iterator it = candidates.constBegin(); it != cend; ++it) {
|
---|
170 | const QString customClassName = (*it)->name();
|
---|
171 | QAction *action = new QAction((*it)->name(), this);
|
---|
172 | connect(action, SIGNAL(triggered()), m_promotionMapper, SLOT(map()));
|
---|
173 | m_promotionMapper->setMapping(action, customClassName);
|
---|
174 | candidatesMenu->addAction(action);
|
---|
175 | }
|
---|
176 | // Sub menu action
|
---|
177 | QAction *subMenuAction = new QAction(m_promoteLabel, this);
|
---|
178 | subMenuAction->setMenu(candidatesMenu);
|
---|
179 | m_promotionActions.push_back(subMenuAction);
|
---|
180 | return CanPromote;
|
---|
181 | }
|
---|
182 |
|
---|
183 | void PromotionTaskMenu::addActions(unsigned separatorFlags, ActionList &actionList)
|
---|
184 | {
|
---|
185 | addActions(formWindow(), separatorFlags, actionList);
|
---|
186 | }
|
---|
187 |
|
---|
188 | void PromotionTaskMenu::addActions(QDesignerFormWindowInterface *fw, unsigned flags,
|
---|
189 | ActionList &actionList)
|
---|
190 | {
|
---|
191 | Q_ASSERT(m_widget);
|
---|
192 | const int previousSize = actionList.size();
|
---|
193 | const PromotionState promotionState = createPromotionActions(fw);
|
---|
194 |
|
---|
195 | // Promotion candidates/demote
|
---|
196 | actionList += m_promotionActions;
|
---|
197 |
|
---|
198 | // Edit action depending on context
|
---|
199 | switch (promotionState) {
|
---|
200 | case CanPromote:
|
---|
201 | actionList += m_EditPromoteToAction;
|
---|
202 | break;
|
---|
203 | case CanDemote:
|
---|
204 | if (!(flags & SuppressGlobalEdit))
|
---|
205 | actionList += m_globalEditAction;
|
---|
206 | if (!languageExtension(fw->core())) {
|
---|
207 | actionList += separatorAction(this);
|
---|
208 | actionList += m_EditSignalsSlotsAction;
|
---|
209 | }
|
---|
210 | break;
|
---|
211 | default:
|
---|
212 | if (!(flags & SuppressGlobalEdit))
|
---|
213 | actionList += m_globalEditAction;
|
---|
214 | break;
|
---|
215 | }
|
---|
216 | // Add separators if required
|
---|
217 | if (actionList.size() > previousSize) {
|
---|
218 | if (flags & LeadingSeparator)
|
---|
219 | actionList.insert(previousSize, separatorAction(this));
|
---|
220 | if (flags & TrailingSeparator)
|
---|
221 | actionList += separatorAction(this);
|
---|
222 | }
|
---|
223 | }
|
---|
224 |
|
---|
225 | void PromotionTaskMenu::addActions(QDesignerFormWindowInterface *fw, unsigned flags, QMenu *menu)
|
---|
226 | {
|
---|
227 | ActionList actionList;
|
---|
228 | addActions(fw, flags, actionList);
|
---|
229 | menu->addActions(actionList);
|
---|
230 | }
|
---|
231 |
|
---|
232 | void PromotionTaskMenu::addActions(unsigned flags, QMenu *menu)
|
---|
233 | {
|
---|
234 | addActions(formWindow(), flags, menu);
|
---|
235 | }
|
---|
236 |
|
---|
237 | void PromotionTaskMenu::promoteTo(QDesignerFormWindowInterface *fw, const QString &customClassName)
|
---|
238 | {
|
---|
239 | Q_ASSERT(m_widget);
|
---|
240 | PromoteToCustomWidgetCommand *cmd = new PromoteToCustomWidgetCommand(fw);
|
---|
241 | cmd->init(promotionSelectionList(fw), customClassName);
|
---|
242 | fw->commandHistory()->push(cmd);
|
---|
243 | }
|
---|
244 |
|
---|
245 |
|
---|
246 | void PromotionTaskMenu::slotPromoteToCustomWidget(const QString &customClassName)
|
---|
247 | {
|
---|
248 | promoteTo(formWindow(), customClassName);
|
---|
249 | }
|
---|
250 |
|
---|
251 | void PromotionTaskMenu::slotDemoteFromCustomWidget()
|
---|
252 | {
|
---|
253 | QDesignerFormWindowInterface *fw = formWindow();
|
---|
254 | const PromotionSelectionList promotedWidgets = promotionSelectionList(fw);
|
---|
255 | Q_ASSERT(!promotedWidgets.empty() && isPromoted(fw->core(), promotedWidgets.front()));
|
---|
256 |
|
---|
257 | // ### use the undo stack
|
---|
258 | DemoteFromCustomWidgetCommand *cmd = new DemoteFromCustomWidgetCommand(fw);
|
---|
259 | cmd->init(promotedWidgets);
|
---|
260 | fw->commandHistory()->push(cmd);
|
---|
261 | }
|
---|
262 |
|
---|
263 | void PromotionTaskMenu::slotEditPromoteTo()
|
---|
264 | {
|
---|
265 | Q_ASSERT(m_widget);
|
---|
266 | // Check whether invoked over a promotable widget
|
---|
267 | QDesignerFormWindowInterface *fw = formWindow();
|
---|
268 | QDesignerFormEditorInterface *core = fw->core();
|
---|
269 | const QString base_class_name = WidgetFactory::classNameOf(core, m_widget);
|
---|
270 | Q_ASSERT(QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(base_class_name));
|
---|
271 | // Show over promotable widget
|
---|
272 | QString promoteToClassName;
|
---|
273 | QDialog *promotionEditor = 0;
|
---|
274 | if (QDesignerLanguageExtension *lang = languageExtension(core))
|
---|
275 | promotionEditor = lang->createPromotionDialog(core, base_class_name, &promoteToClassName, fw);
|
---|
276 | if (!promotionEditor)
|
---|
277 | promotionEditor = new QDesignerPromotionDialog(core, fw, base_class_name, &promoteToClassName);
|
---|
278 | if (promotionEditor->exec() == QDialog::Accepted && !promoteToClassName.isEmpty()) {
|
---|
279 | promoteTo(fw, promoteToClassName);
|
---|
280 | }
|
---|
281 | delete promotionEditor;
|
---|
282 | }
|
---|
283 |
|
---|
284 | void PromotionTaskMenu::slotEditPromotedWidgets()
|
---|
285 | {
|
---|
286 | // Global context, show over non-promotable widget
|
---|
287 | QDesignerFormWindowInterface *fw = formWindow();
|
---|
288 | if (!fw)
|
---|
289 | return;
|
---|
290 | editPromotedWidgets(fw->core(), fw);
|
---|
291 | }
|
---|
292 |
|
---|
293 | PromotionTaskMenu::PromotionSelectionList PromotionTaskMenu::promotionSelectionList(QDesignerFormWindowInterface *formWindow) const
|
---|
294 | {
|
---|
295 | // In multi selection mode, check for a homogenous selection (same class, same promotion state)
|
---|
296 | // and return the list if this is the case. Also make sure m_widget
|
---|
297 | // is the last widget in the list so that it is re-selected as the last
|
---|
298 | // widget by the promotion commands.
|
---|
299 |
|
---|
300 | PromotionSelectionList rc;
|
---|
301 |
|
---|
302 | if (m_mode != ModeSingleWidget) {
|
---|
303 | QDesignerFormEditorInterface *core = formWindow->core();
|
---|
304 | const QDesignerIntrospectionInterface *intro = core->introspection();
|
---|
305 | const QString className = intro->metaObject(m_widget)->className();
|
---|
306 | const bool promoted = isPromoted(formWindow->core(), m_widget);
|
---|
307 | // Just in case someone plugged an old-style Object Inspector
|
---|
308 | if (QDesignerObjectInspector *designerObjectInspector = qobject_cast<QDesignerObjectInspector *>(core->objectInspector())) {
|
---|
309 | Selection s;
|
---|
310 | designerObjectInspector->getSelection(s);
|
---|
311 | // Find objects of similar state
|
---|
312 | const QWidgetList &source = m_mode == ModeManagedMultiSelection ? s.managed : s.unmanaged;
|
---|
313 | const QWidgetList::const_iterator cend = source.constEnd();
|
---|
314 | for (QWidgetList::const_iterator it = source.constBegin(); it != cend; ++it) {
|
---|
315 | QWidget *w = *it;
|
---|
316 | if (w != m_widget) {
|
---|
317 | // Selection state mismatch
|
---|
318 | if (intro->metaObject(w)->className() != className || isPromoted(core, w) != promoted)
|
---|
319 | return PromotionSelectionList();
|
---|
320 | rc.push_back(w);
|
---|
321 | }
|
---|
322 | }
|
---|
323 | }
|
---|
324 | }
|
---|
325 |
|
---|
326 | rc.push_back(m_widget);
|
---|
327 | return rc;
|
---|
328 | }
|
---|
329 |
|
---|
330 | QDesignerFormWindowInterface *PromotionTaskMenu::formWindow() const
|
---|
331 | {
|
---|
332 | // Use the QObject overload of QDesignerFormWindowInterface::findFormWindow since that works
|
---|
333 | // for QDesignerMenus also.
|
---|
334 | QObject *o = m_widget;
|
---|
335 | QDesignerFormWindowInterface *result = QDesignerFormWindowInterface::findFormWindow(o);
|
---|
336 | Q_ASSERT(result != 0);
|
---|
337 | return result;
|
---|
338 | }
|
---|
339 |
|
---|
340 | void PromotionTaskMenu::editPromotedWidgets(QDesignerFormEditorInterface *core, QWidget* parent) {
|
---|
341 | QDesignerLanguageExtension *lang = languageExtension(core);
|
---|
342 | // Show over non-promotable widget
|
---|
343 | QDialog *promotionEditor = 0;
|
---|
344 | if (lang)
|
---|
345 | lang->createPromotionDialog(core, parent);
|
---|
346 | if (!promotionEditor)
|
---|
347 | promotionEditor = new QDesignerPromotionDialog(core, parent);
|
---|
348 | promotionEditor->exec();
|
---|
349 | delete promotionEditor;
|
---|
350 | }
|
---|
351 |
|
---|
352 | void PromotionTaskMenu::slotEditSignalsSlots()
|
---|
353 | {
|
---|
354 | QDesignerFormWindowInterface *fw = formWindow();
|
---|
355 | if (!fw)
|
---|
356 | return;
|
---|
357 | SignalSlotDialog::editPromotedClass(fw->core(), m_widget, fw);
|
---|
358 | }
|
---|
359 | } // namespace qdesigner_internal
|
---|
360 |
|
---|
361 | QT_END_NAMESPACE
|
---|