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