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
codedialog.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
5#include "codedialog_p.h"
7#include "iconloader_p.h"
8
9#include <texteditfindwidget_p.h>
10
11#include <QtWidgets/qapplication.h>
12#if QT_CONFIG(clipboard)
13#include <QtGui/qclipboard.h>
14#endif
15#include <QtWidgets/qdialogbuttonbox.h>
16#include <QtWidgets/qfiledialog.h>
17#include <QtWidgets/qmessagebox.h>
18#include <QtWidgets/qpushbutton.h>
19#include <QtWidgets/qtextedit.h>
20#include <QtWidgets/qtoolbar.h>
21#include <QtWidgets/qboxlayout.h>
22
23#include <QtGui/qaction.h>
24#include <QtGui/qevent.h>
25#include <QtGui/qfontdatabase.h>
26#include <QtGui/qfontmetrics.h>
27#include <QtGui/qicon.h>
28
29#include <QtCore/qdebug.h>
30#include <QtCore/qdir.h>
31#include <QtCore/qmimedatabase.h>
32#include <QtCore/qtemporaryfile.h>
33
35
36using namespace Qt::StringLiterals;
37
38namespace qdesigner_internal {
39// ----------------- CodeDialogPrivate
48
49CodeDialog::CodeDialogPrivate::CodeDialogPrivate()
50 : m_textEdit(new QTextEdit)
51 , m_findWidget(new TextEditFindWidget)
52{
53}
54
55// ----------------- CodeDialog
56CodeDialog::CodeDialog(QWidget *parent) :
57 QDialog(parent),
58 m_impl(new CodeDialogPrivate)
59{
60 QVBoxLayout *vBoxLayout = new QVBoxLayout;
61
62 // Edit tool bar
63 QToolBar *toolBar = new QToolBar;
64
65 const QIcon saveIcon = createIconSet(QIcon::ThemeIcon::DocumentSave,
66 "filesave.png"_L1);
67 QAction *saveAction = toolBar->addAction(saveIcon, tr("Save..."));
68 connect(saveAction, &QAction::triggered, this, &CodeDialog::slotSaveAs);
69
70#if QT_CONFIG(clipboard)
71 const QIcon copyIcon = createIconSet(QIcon::ThemeIcon::EditCopy,
72 "editcopy.png"_L1);
73 QAction *copyAction = toolBar->addAction(copyIcon, tr("Copy All"));
74 connect(copyAction, &QAction::triggered, this, &CodeDialog::copyAll);
75#endif
76
77 toolBar->addAction(m_impl->m_findWidget->createFindAction(toolBar));
78
79 vBoxLayout->addWidget(toolBar);
80
81 // Edit
82 m_impl->m_textEdit->setReadOnly(true);
83 const auto font = QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont);
84 const int editorWidth = QFontMetrics(font, this).averageCharWidth() * 100;
85 m_impl->m_textEdit->setFont(font);
86 m_impl->m_textEdit->setMinimumSize(QSize(
87 qMax(editorWidth, m_impl->m_findWidget->minimumSize().width()),
88 500));
89 vBoxLayout->addWidget(m_impl->m_textEdit);
90
91 // Find
92 m_impl->m_findWidget->setTextEdit(m_impl->m_textEdit);
93 vBoxLayout->addWidget(m_impl->m_findWidget);
94
95 // Button box
96 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
97 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
98
99 // Disable auto default
100 QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close);
101 closeButton->setAutoDefault(false);
102 vBoxLayout->addWidget(buttonBox);
103
104 setLayout(vBoxLayout);
105}
106
107CodeDialog::~CodeDialog()
108{
109 delete m_impl;
110}
111
112void CodeDialog::setCode(const QString &code)
113{
114 m_impl->m_textEdit->setPlainText(code);
115}
116
117QString CodeDialog::code() const
118{
119 return m_impl->m_textEdit->toPlainText();
120}
121
122void CodeDialog::setFormFileName(const QString &f)
123{
124 m_impl->m_formFileName = f;
125}
126
127QString CodeDialog::formFileName() const
128{
129 return m_impl->m_formFileName;
130}
131
132void CodeDialog::setMimeType(const QString &m)
133{
134 m_impl->m_mimeType = m;
135}
136
137bool CodeDialog::generateCode(const QDesignerFormWindowInterface *fw,
138 UicLanguage language,
139 QString *code,
140 QString *errorMessage)
141{
142 // Generate temporary file name similar to form file name
143 // (for header guards)
144 QString tempPattern = QDir::tempPath();
145 if (!tempPattern.endsWith(QDir::separator())) // platform-dependant
146 tempPattern += QDir::separator();
147 const QString fileName = fw->fileName();
148 if (fileName.isEmpty()) {
149 tempPattern += "designer"_L1;
150 } else {
151 tempPattern += QFileInfo(fileName).baseName();
152 }
153 tempPattern += "XXXXXX.ui"_L1;
154 // Write to temp file
155 QTemporaryFile tempFormFile(tempPattern);
156
157 tempFormFile.setAutoRemove(true);
158 if (!tempFormFile.open()) {
159 *errorMessage = tr("A temporary form file could not be created in %1.").arg(QDir::tempPath());
160 return false;
161 }
162 const QString tempFormFileName = tempFormFile.fileName();
163 tempFormFile.write(fw->contents().toUtf8());
164 if (!tempFormFile.flush()) {
165 *errorMessage = tr("The temporary form file %1 could not be written.").arg(tempFormFileName);
166 return false;
167 }
168 tempFormFile.close();
169 // Run uic
170 QByteArray rc;
171 if (!runUIC(tempFormFileName, language, rc, *errorMessage))
172 return false;
173 *code = QString::fromUtf8(rc);
174 return true;
175}
176
177bool CodeDialog::showCodeDialog(const QDesignerFormWindowInterface *fw,
178 UicLanguage language,
179 QWidget *parent,
180 QString *errorMessage)
181{
182 QString code;
183 if (!generateCode(fw, language, &code, errorMessage))
184 return false;
185
186 auto dialog = new CodeDialog(parent);
187 dialog->setModal(false);
188 dialog->setAttribute(Qt::WA_DeleteOnClose);
189 dialog->setCode(code);
190 dialog->setFormFileName(fw->fileName());
191 QLatin1StringView languageName;
192 switch (language) {
193 case UicLanguage::Cpp:
194 languageName = "C++"_L1;
195 dialog->setMimeType(u"text/x-chdr"_s);
196 break;
197 case UicLanguage::Python:
198 languageName = "Python"_L1;
199 dialog->setMimeType(u"text/x-python"_s);
200 break;
201 }
202 dialog->setWindowTitle(tr("%1 - [%2 Code]").
203 arg(fw->mainContainer()->windowTitle(), languageName));
204 dialog->show();
205 return true;
206}
207
208void CodeDialog::slotSaveAs()
209{
210 // build the default relative name 'ui_sth.h'
211 QMimeDatabase mimeDb;
212 const QString suffix = mimeDb.mimeTypeForName(m_impl->m_mimeType).preferredSuffix();
213
214 // file dialog
215 QFileDialog fileDialog(this, tr("Save Code"));
216 fileDialog.setMimeTypeFilters(QStringList(m_impl->m_mimeType));
217 fileDialog.setAcceptMode(QFileDialog::AcceptSave);
218 fileDialog.setDefaultSuffix(suffix);
219 const QString uiFile = formFileName();
220 if (!uiFile.isEmpty()) {
221 QFileInfo uiFi(uiFile);
222 fileDialog.setDirectory(uiFi.absolutePath());
223 fileDialog.selectFile("ui_"_L1 + uiFi.baseName()
224 + '.'_L1 + suffix);
225 }
226
227 while (true) {
228 if (fileDialog.exec() != QDialog::Accepted)
229 break;
230 const QString fileName = fileDialog.selectedFiles().constFirst();
231
232 QFile file(fileName);
233 if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) {
234 warning(tr("The file %1 could not be opened: %2")
235 .arg(fileName, file.errorString()));
236 continue;
237 }
238 file.write(code().toUtf8());
239 if (!file.flush()) {
240 warning(tr("The file %1 could not be written: %2")
241 .arg(fileName, file.errorString()));
242 continue;
243 }
244 file.close();
245 break;
246 }
247}
248
249void CodeDialog::warning(const QString &msg)
250{
251 QMessageBox::warning(
252 this, tr("%1 - Error").arg(windowTitle()),
253 msg, QMessageBox::Close);
254}
255
256#if QT_CONFIG(clipboard)
257void CodeDialog::copyAll()
258{
259 QApplication::clipboard()->setText(code());
260}
261#endif
262
263} // namespace qdesigner_internal
264
265QT_END_NAMESPACE
A search bar that is commonly added below the searchable text.
Combined button and popup list for selecting options.