Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qdesigner_formwindow.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
7
8// sdk
9#include <QtDesigner/abstractformwindow.h>
10#include <QtDesigner/abstractformeditor.h>
11#include <QtDesigner/propertysheet.h>
12#include <QtDesigner/abstractpropertyeditor.h>
13#include <QtDesigner/abstractformwindowmanager.h>
14#include <QtDesigner/taskmenu.h>
15#include <QtDesigner/qextensionmanager.h>
16
17#include <QtWidgets/qfiledialog.h>
18#include <QtWidgets/qmessagebox.h>
19#include <QtWidgets/qpushbutton.h>
20#include <QtWidgets/qboxlayout.h>
21
22#include <QtGui/qaction.h>
23#include <QtGui/qevent.h>
24#include <QtGui/qundostack.h>
25
26#include <QtCore/qfile.h>
27#include <QtCore/qregularexpression.h>
28
30
31using namespace Qt::StringLiterals;
32
33QDesignerFormWindow::QDesignerFormWindow(QDesignerFormWindowInterface *editor, QDesignerWorkbench *workbench, QWidget *parent, Qt::WindowFlags flags)
34 : QWidget(parent, flags),
35 m_editor(editor),
36 m_workbench(workbench),
37 m_action(new QAction(this))
38{
39 Q_ASSERT(workbench);
40
41 setMaximumSize(0xFFF, 0xFFF);
42 QDesignerFormEditorInterface *core = workbench->core();
43
44 if (m_editor) {
45 m_editor->setParent(this);
46 } else {
47 m_editor = core->formWindowManager()->createFormWindow(this);
48 }
49
50 QVBoxLayout *l = new QVBoxLayout(this);
51 l->setContentsMargins(QMargins());
52 l->addWidget(m_editor);
53
54 m_action->setCheckable(true);
55
56 connect(m_editor->commandHistory(), &QUndoStack::indexChanged, this, &QDesignerFormWindow::updateChanged);
57 connect(m_editor.data(), &QDesignerFormWindowInterface::geometryChanged,
58 this, &QDesignerFormWindow::slotGeometryChanged);
59}
60
66
67QAction *QDesignerFormWindow::action() const
68{
69 return m_action;
70}
71
73{
74 switch (e->type()) {
75 case QEvent::WindowTitleChange:
76 m_action->setText(windowTitle().remove("[*]"_L1));
77 break;
78 case QEvent::WindowIconChange:
79 m_action->setIcon(windowIcon());
80 break;
81 case QEvent::WindowStateChange: {
82 const QWindowStateChangeEvent *wsce = static_cast<const QWindowStateChangeEvent *>(e);
83 const bool wasMinimized = Qt::WindowMinimized & wsce->oldState();
84 const bool isMinimizedNow = isMinimized();
85 if (wasMinimized != isMinimizedNow )
86 emit minimizationStateChanged(m_editor, isMinimizedNow);
87 }
88 break;
89 default:
90 break;
91 }
92 QWidget::changeEvent(e);
93}
94
96{
97 const QPoint point(0, 0);
98 // If we have a container, we want to be just as big.
99 // QMdiSubWindow attempts to resize its children to sizeHint() when switching user interface modes.
100 if (QWidget *mainContainer = m_editor->mainContainer())
101 return QRect(point, mainContainer->size());
102
103 return QRect(point, sizeHint());
104}
105
106QDesignerFormWindowInterface *QDesignerFormWindow::editor() const
107{
108 return m_editor;
109}
110
112{
113 return m_workbench;
114}
115
117{
118 // Set up handling of file name changes and set initial title.
119 if (!m_windowTitleInitialized) {
120 m_windowTitleInitialized = true;
121 if (m_editor) {
122 connect(m_editor.data(), &QDesignerFormWindowInterface::fileNameChanged,
123 this, &QDesignerFormWindow::updateWindowTitle);
124 updateWindowTitle(m_editor->fileName());
125 updateChanged();
126 }
127 }
128 show();
129}
130
131int QDesignerFormWindow::getNumberOfUntitledWindows() const
132{
133 const int totalWindows = m_workbench->formWindowCount();
134 if (!totalWindows)
135 return 0;
136
137 int maxUntitled = 0;
138 // Find the number of untitled windows excluding ourselves.
139 // Do not fall for 'untitled.ui', match with modified place holder.
140 // This will cause some problems with i18n, but for now I need the string to be "static"
141 static const QRegularExpression rx(u"untitled( (\\d+))?\\[\\*\\]$"_s);
142 Q_ASSERT(rx.isValid());
143 for (int i = 0; i < totalWindows; ++i) {
144 QDesignerFormWindow *fw = m_workbench->formWindow(i);
145 if (fw != this) {
146 const QString title = m_workbench->formWindow(i)->windowTitle();
147 const QRegularExpressionMatch match = rx.match(title);
148 if (match.hasMatch()) {
149 if (maxUntitled == 0)
150 ++maxUntitled;
151 if (match.lastCapturedIndex() >= 2) {
152 const auto numberCapture = match.capturedView(2);
153 if (!numberCapture.isEmpty())
154 maxUntitled = qMax(numberCapture.toInt(), maxUntitled);
155 }
156 }
157 }
158 }
159 return maxUntitled;
160}
161
162void QDesignerFormWindow::updateWindowTitle(const QString &fileName)
163{
164 if (!m_windowTitleInitialized) {
165 m_windowTitleInitialized = true;
166 if (m_editor)
167 connect(m_editor.data(), &QDesignerFormWindowInterface::fileNameChanged,
168 this, &QDesignerFormWindow::updateWindowTitle);
169 }
170
171 QString fileNameTitle;
172 if (fileName.isEmpty()) {
173 fileNameTitle += "untitled"_L1;
174 if (const int maxUntitled = getNumberOfUntitledWindows()) {
175 fileNameTitle += u' ' + QString::number(maxUntitled + 1);
176 }
177 } else {
178 fileNameTitle = QFileInfo(fileName).fileName();
179 }
180
181 if (const QWidget *mc = m_editor->mainContainer()) {
182 setWindowIcon(mc->windowIcon());
183 setWindowTitle(tr("%1 - %2[*]").arg(mc->windowTitle(), fileNameTitle));
184 } else {
185 setWindowTitle(fileNameTitle);
186 }
187}
188
189void QDesignerFormWindow::closeEvent(QCloseEvent *ev)
190{
191 if (m_editor->isDirty()) {
192 raise();
193 QMessageBox box(QMessageBox::Information, tr("Save Form?"),
194 tr("Do you want to save the changes to this document before closing?"),
195 QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save, m_editor);
196 box.setInformativeText(tr("If you don't save, your changes will be lost."));
197 box.setWindowModality(Qt::WindowModal);
198 static_cast<QPushButton *>(box.button(QMessageBox::Save))->setDefault(true);
199
200 switch (box.exec()) {
201 case QMessageBox::Save: {
202 bool ok = workbench()->saveForm(m_editor);
203 ev->setAccepted(ok);
204 m_editor->setDirty(!ok);
205 break;
206 }
207 case QMessageBox::Discard:
208 m_editor->setDirty(false); // Not really necessary, but stops problems if we get close again.
209 ev->accept();
210 break;
211 case QMessageBox::Cancel:
212 ev->ignore();
213 break;
214 }
215 }
216}
217
218void QDesignerFormWindow::updateChanged()
219{
220 // Sometimes called after form window destruction.
221 if (m_editor) {
222 setWindowModified(m_editor->isDirty());
223 updateWindowTitle(m_editor->fileName());
224 }
225}
226
227void QDesignerFormWindow::resizeEvent(QResizeEvent *rev)
228{
229 if(m_initialized) {
230 m_editor->setDirty(true);
231 setWindowModified(true);
232 }
233
234 m_initialized = true;
235 QWidget::resizeEvent(rev);
236}
237
238void QDesignerFormWindow::slotGeometryChanged()
239{
240 // If the form window changes, re-update the geometry of the current widget in the property editor.
241 // Note that in the case of layouts, non-maincontainer widgets must also be updated,
242 // so, do not do it for the main container only
243 const QDesignerFormEditorInterface *core = m_editor->core();
244 QObject *object = core->propertyEditor()->object();
245 if (object == nullptr || !object->isWidgetType())
246 return;
247 static const QString geometryProperty = u"geometry"_s;
248 const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), object);
249 const int geometryIndex = sheet->indexOf(geometryProperty);
250 if (geometryIndex == -1)
251 return;
252 core->propertyEditor()->setPropertyValue(geometryProperty, sheet->property(geometryIndex));
253}
254
255QT_END_NAMESPACE
QDesignerFormWindowInterface * editor() const
void closeEvent(QCloseEvent *ev) override
This event handler is called with the given event when Qt receives a window close request for a top-l...
QDesignerWorkbench * workbench() const
void changeEvent(QEvent *e) override
This event handler can be reimplemented to handle state changes.
void resizeEvent(QResizeEvent *rev) override
This event handler can be reimplemented in a subclass to receive widget resize events which are passe...
QDesignerFormEditorInterface * core() const
void removeFormWindow(QDesignerFormWindow *formWindow)
Combined button and popup list for selecting options.