// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "codedialog_p.h" #include "qdesigner_utils_p.h" #include "iconloader_p.h" #include #include #if QT_CONFIG(clipboard) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; namespace qdesigner_internal { // ----------------- CodeDialogPrivate struct CodeDialog::CodeDialogPrivate { CodeDialogPrivate(); QTextEdit *m_textEdit; TextEditFindWidget *m_findWidget; QString m_formFileName; QString m_mimeType; }; CodeDialog::CodeDialogPrivate::CodeDialogPrivate() : m_textEdit(new QTextEdit) , m_findWidget(new TextEditFindWidget) { } // ----------------- CodeDialog CodeDialog::CodeDialog(QWidget *parent) : QDialog(parent), m_impl(new CodeDialogPrivate) { QVBoxLayout *vBoxLayout = new QVBoxLayout; // Edit tool bar QToolBar *toolBar = new QToolBar; const QIcon saveIcon = createIconSet(QIcon::ThemeIcon::DocumentSave, "filesave.png"_L1); QAction *saveAction = toolBar->addAction(saveIcon, tr("Save...")); connect(saveAction, &QAction::triggered, this, &CodeDialog::slotSaveAs); #if QT_CONFIG(clipboard) const QIcon copyIcon = createIconSet(QIcon::ThemeIcon::EditCopy, "editcopy.png"_L1); QAction *copyAction = toolBar->addAction(copyIcon, tr("Copy All")); connect(copyAction, &QAction::triggered, this, &CodeDialog::copyAll); #endif toolBar->addAction(m_impl->m_findWidget->createFindAction(toolBar)); vBoxLayout->addWidget(toolBar); // Edit m_impl->m_textEdit->setReadOnly(true); const auto font = QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont); const int editorWidth = QFontMetrics(font, this).averageCharWidth() * 100; m_impl->m_textEdit->setFont(font); m_impl->m_textEdit->setMinimumSize(QSize( qMax(editorWidth, m_impl->m_findWidget->minimumSize().width()), 500)); vBoxLayout->addWidget(m_impl->m_textEdit); // Find m_impl->m_findWidget->setTextEdit(m_impl->m_textEdit); vBoxLayout->addWidget(m_impl->m_findWidget); // Button box QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); // Disable auto default QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close); closeButton->setAutoDefault(false); vBoxLayout->addWidget(buttonBox); setLayout(vBoxLayout); } CodeDialog::~CodeDialog() { delete m_impl; } void CodeDialog::setCode(const QString &code) { m_impl->m_textEdit->setPlainText(code); } QString CodeDialog::code() const { return m_impl->m_textEdit->toPlainText(); } void CodeDialog::setFormFileName(const QString &f) { m_impl->m_formFileName = f; } QString CodeDialog::formFileName() const { return m_impl->m_formFileName; } void CodeDialog::setMimeType(const QString &m) { m_impl->m_mimeType = m; } bool CodeDialog::generateCode(const QDesignerFormWindowInterface *fw, UicLanguage language, QString *code, QString *errorMessage) { // Generate temporary file name similar to form file name // (for header guards) QString tempPattern = QDir::tempPath(); if (!tempPattern.endsWith(QDir::separator())) // platform-dependant tempPattern += QDir::separator(); const QString fileName = fw->fileName(); if (fileName.isEmpty()) { tempPattern += "designer"_L1; } else { tempPattern += QFileInfo(fileName).baseName(); } tempPattern += "XXXXXX.ui"_L1; // Write to temp file QTemporaryFile tempFormFile(tempPattern); tempFormFile.setAutoRemove(true); if (!tempFormFile.open()) { *errorMessage = tr("A temporary form file could not be created in %1.").arg(QDir::tempPath()); return false; } const QString tempFormFileName = tempFormFile.fileName(); tempFormFile.write(fw->contents().toUtf8()); if (!tempFormFile.flush()) { *errorMessage = tr("The temporary form file %1 could not be written.").arg(tempFormFileName); return false; } tempFormFile.close(); // Run uic QByteArray rc; if (!runUIC(tempFormFileName, language, rc, *errorMessage)) return false; *code = QString::fromUtf8(rc); return true; } bool CodeDialog::showCodeDialog(const QDesignerFormWindowInterface *fw, UicLanguage language, QWidget *parent, QString *errorMessage) { QString code; if (!generateCode(fw, language, &code, errorMessage)) return false; auto dialog = new CodeDialog(parent); dialog->setModal(false); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setCode(code); dialog->setFormFileName(fw->fileName()); QLatin1StringView languageName; switch (language) { case UicLanguage::Cpp: languageName = "C++"_L1; dialog->setMimeType(u"text/x-chdr"_s); break; case UicLanguage::Python: languageName = "Python"_L1; dialog->setMimeType(u"text/x-python"_s); break; } dialog->setWindowTitle(tr("%1 - [%2 Code]"). arg(fw->mainContainer()->windowTitle(), languageName)); dialog->show(); return true; } void CodeDialog::slotSaveAs() { // build the default relative name 'ui_sth.h' QMimeDatabase mimeDb; const QString suffix = mimeDb.mimeTypeForName(m_impl->m_mimeType).preferredSuffix(); // file dialog QFileDialog fileDialog(this, tr("Save Code")); fileDialog.setMimeTypeFilters(QStringList(m_impl->m_mimeType)); fileDialog.setAcceptMode(QFileDialog::AcceptSave); fileDialog.setDefaultSuffix(suffix); const QString uiFile = formFileName(); if (!uiFile.isEmpty()) { QFileInfo uiFi(uiFile); fileDialog.setDirectory(uiFi.absolutePath()); fileDialog.selectFile("ui_"_L1 + uiFi.baseName() + '.'_L1 + suffix); } while (true) { if (fileDialog.exec() != QDialog::Accepted) break; const QString fileName = fileDialog.selectedFiles().constFirst(); QFile file(fileName); if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) { warning(tr("The file %1 could not be opened: %2") .arg(fileName, file.errorString())); continue; } file.write(code().toUtf8()); if (!file.flush()) { warning(tr("The file %1 could not be written: %2") .arg(fileName, file.errorString())); continue; } file.close(); break; } } void CodeDialog::warning(const QString &msg) { QMessageBox::warning( this, tr("%1 - Error").arg(windowTitle()), msg, QMessageBox::Close); } #if QT_CONFIG(clipboard) void CodeDialog::copyAll() { QApplication::clipboard()->setText(code()); } #endif } // namespace qdesigner_internal QT_END_NAMESPACE