1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "codedialog_p.h"
30#include "qdesigner_utils_p.h"
31#include "iconloader_p.h"
32
33#include <texteditfindwidget.h>
34
35#include <QtWidgets/qaction.h>
36#include <QtWidgets/qapplication.h>
37#if QT_CONFIG(clipboard)
38#include <QtGui/qclipboard.h>
39#endif
40#include <QtWidgets/qdialogbuttonbox.h>
41#include <QtWidgets/qfiledialog.h>
42#include <QtGui/qicon.h>
43#include <QtGui/qevent.h>
44#include <QtWidgets/qmessagebox.h>
45#include <QtWidgets/qpushbutton.h>
46#include <QtWidgets/qtextedit.h>
47#include <QtWidgets/qtoolbar.h>
48#include <QtWidgets/qboxlayout.h>
49
50#include <QtCore/qdebug.h>
51#include <QtCore/qdir.h>
52#include <QtCore/qmimedatabase.h>
53#include <QtCore/qtemporaryfile.h>
54
55QT_BEGIN_NAMESPACE
56
57namespace qdesigner_internal {
58// ----------------- CodeDialogPrivate
59struct CodeDialog::CodeDialogPrivate {
60 CodeDialogPrivate();
61
62 QTextEdit *m_textEdit;
63 TextEditFindWidget *m_findWidget;
64 QString m_formFileName;
65 QString m_mimeType;
66};
67
68CodeDialog::CodeDialogPrivate::CodeDialogPrivate()
69 : m_textEdit(new QTextEdit)
70 , m_findWidget(new TextEditFindWidget)
71{
72}
73
74// ----------------- CodeDialog
75CodeDialog::CodeDialog(QWidget *parent) :
76 QDialog(parent),
77 m_impl(new CodeDialogPrivate)
78{
79 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
80 QVBoxLayout *vBoxLayout = new QVBoxLayout;
81
82 // Edit tool bar
83 QToolBar *toolBar = new QToolBar;
84
85 const QIcon saveIcon = createIconSet(QStringLiteral("filesave.png"));
86 QAction *saveAction = toolBar->addAction(icon: saveIcon, text: tr(s: "Save..."));
87 connect(sender: saveAction, signal: &QAction::triggered, receiver: this, slot: &CodeDialog::slotSaveAs);
88
89#if QT_CONFIG(clipboard)
90 const QIcon copyIcon = createIconSet(QStringLiteral("editcopy.png"));
91 QAction *copyAction = toolBar->addAction(icon: copyIcon, text: tr(s: "Copy All"));
92 connect(sender: copyAction, signal: &QAction::triggered, receiver: this, slot: &CodeDialog::copyAll);
93#endif
94
95 toolBar->addAction(action: m_impl->m_findWidget->createFindAction(parent: toolBar));
96
97 vBoxLayout->addWidget(toolBar);
98
99 // Edit
100 m_impl->m_textEdit->setReadOnly(true);
101 m_impl->m_textEdit->setMinimumSize(QSize(
102 m_impl->m_findWidget->minimumSize().width(),
103 500));
104 vBoxLayout->addWidget(m_impl->m_textEdit);
105
106 // Find
107 m_impl->m_findWidget->setTextEdit(m_impl->m_textEdit);
108 vBoxLayout->addWidget(m_impl->m_findWidget);
109
110 // Button box
111 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
112 connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, receiver: this, slot: &QDialog::reject);
113
114 // Disable auto default
115 QPushButton *closeButton = buttonBox->button(which: QDialogButtonBox::Close);
116 closeButton->setAutoDefault(false);
117 vBoxLayout->addWidget(buttonBox);
118
119 setLayout(vBoxLayout);
120}
121
122CodeDialog::~CodeDialog()
123{
124 delete m_impl;
125}
126
127void CodeDialog::setCode(const QString &code)
128{
129 m_impl->m_textEdit->setPlainText(code);
130}
131
132QString CodeDialog::code() const
133{
134 return m_impl->m_textEdit->toPlainText();
135}
136
137void CodeDialog::setFormFileName(const QString &f)
138{
139 m_impl->m_formFileName = f;
140}
141
142QString CodeDialog::formFileName() const
143{
144 return m_impl->m_formFileName;
145}
146
147void CodeDialog::setMimeType(const QString &m)
148{
149 m_impl->m_mimeType = m;
150}
151
152bool CodeDialog::generateCode(const QDesignerFormWindowInterface *fw,
153 UicLanguage language,
154 QString *code,
155 QString *errorMessage)
156{
157 // Generate temporary file name similar to form file name
158 // (for header guards)
159 QString tempPattern = QDir::tempPath();
160 if (!tempPattern.endsWith(c: QDir::separator())) // platform-dependant
161 tempPattern += QDir::separator();
162 const QString fileName = fw->fileName();
163 if (fileName.isEmpty()) {
164 tempPattern += QStringLiteral("designer");
165 } else {
166 tempPattern += QFileInfo(fileName).baseName();
167 }
168 tempPattern += QStringLiteral("XXXXXX.ui");
169 // Write to temp file
170 QTemporaryFile tempFormFile(tempPattern);
171
172 tempFormFile.setAutoRemove(true);
173 if (!tempFormFile.open()) {
174 *errorMessage = tr(s: "A temporary form file could not be created in %1.").arg(a: QDir::tempPath());
175 return false;
176 }
177 const QString tempFormFileName = tempFormFile.fileName();
178 tempFormFile.write(data: fw->contents().toUtf8());
179 if (!tempFormFile.flush()) {
180 *errorMessage = tr(s: "The temporary form file %1 could not be written.").arg(a: tempFormFileName);
181 return false;
182 }
183 tempFormFile.close();
184 // Run uic
185 QByteArray rc;
186 if (!runUIC(fileName: tempFormFileName, language, ba&: rc, errorMessage&: *errorMessage))
187 return false;
188 *code = QString::fromUtf8(str: rc);
189 return true;
190}
191
192bool CodeDialog::showCodeDialog(const QDesignerFormWindowInterface *fw,
193 UicLanguage language,
194 QWidget *parent,
195 QString *errorMessage)
196{
197 QString code;
198 if (!generateCode(fw, language, code: &code, errorMessage))
199 return false;
200
201 auto dialog = new CodeDialog(parent);
202 dialog->setModal(false);
203 dialog->setAttribute(Qt::WA_DeleteOnClose);
204 dialog->setCode(code);
205 dialog->setFormFileName(fw->fileName());
206 QString languageName;
207 switch (language) {
208 case UicLanguage::Cpp:
209 languageName = QLatin1String("C++");
210 dialog->setMimeType(QLatin1String("text/x-chdr"));
211 break;
212 case UicLanguage::Python:
213 languageName = QLatin1String("Python");
214 dialog->setMimeType(QLatin1String("text/x-python"));
215 break;
216 }
217 dialog->setWindowTitle(tr(s: "%1 - [%2 Code]").
218 arg(args: fw->mainContainer()->windowTitle(), args&: languageName));
219 dialog->show();
220 return true;
221}
222
223void CodeDialog::slotSaveAs()
224{
225 // build the default relative name 'ui_sth.h'
226 QMimeDatabase mimeDb;
227 const QString suffix = mimeDb.mimeTypeForName(nameOrAlias: m_impl->m_mimeType).preferredSuffix();
228
229 // file dialog
230 QFileDialog fileDialog(this, tr(s: "Save Code"));
231 fileDialog.setMimeTypeFilters(QStringList(m_impl->m_mimeType));
232 fileDialog.setAcceptMode(QFileDialog::AcceptSave);
233 fileDialog.setDefaultSuffix(suffix);
234 const QString uiFile = formFileName();
235 if (!uiFile.isEmpty()) {
236 QFileInfo uiFi(uiFile);
237 fileDialog.setDirectory(uiFi.absolutePath());
238 fileDialog.selectFile(filename: QLatin1String("ui_") + uiFi.baseName()
239 + QLatin1Char('.') + suffix);
240 }
241
242 while (true) {
243 if (fileDialog.exec() != QDialog::Accepted)
244 break;
245 const QString fileName = fileDialog.selectedFiles().constFirst();
246
247 QFile file(fileName);
248 if (!file.open(flags: QIODevice::WriteOnly|QIODevice::Text)) {
249 warning(msg: tr(s: "The file %1 could not be opened: %2")
250 .arg(args: fileName, args: file.errorString()));
251 continue;
252 }
253 file.write(data: code().toUtf8());
254 if (!file.flush()) {
255 warning(msg: tr(s: "The file %1 could not be written: %2")
256 .arg(args: fileName, args: file.errorString()));
257 continue;
258 }
259 file.close();
260 break;
261 }
262}
263
264void CodeDialog::warning(const QString &msg)
265{
266 QMessageBox::warning(
267 parent: this, title: tr(s: "%1 - Error").arg(a: windowTitle()),
268 text: msg, buttons: QMessageBox::Close);
269}
270
271#if QT_CONFIG(clipboard)
272void CodeDialog::copyAll()
273{
274 QApplication::clipboard()->setText(code());
275}
276#endif
277
278} // namespace qdesigner_internal
279
280QT_END_NAMESPACE
281

source code of qttools/src/designer/src/lib/shared/codedialog.cpp