File indexing completed on 2024-05-05 05:52:18

0001 /*  This file is part of the Kate project.
0002  *  Based on the snippet plugin from KDevelop 4.
0003  *
0004  *  SPDX-FileCopyrightText: 2007 Robert Gruber <rgruber@users.sourceforge.net>
0005  *  SPDX-FileCopyrightText: 2010 Milian Wolff <mail@milianw.de>
0006  *  SPDX-FileCopyrightText: 2012 Christoph Cullmann <cullmann@kde.org>
0007  *
0008  *  SPDX-License-Identifier: LGPL-2.0-or-later
0009  */
0010 
0011 #include "editsnippet.h"
0012 
0013 #include "ui_editsnippet.h"
0014 
0015 #include "snippet.h"
0016 #include "snippetrepository.h"
0017 #include "snippetstore.h"
0018 
0019 #include <KConfigGroup>
0020 #include <KLocalizedString>
0021 #include <KMessageBox>
0022 #include <KSharedConfig>
0023 
0024 #include <QAction>
0025 #include <QPushButton>
0026 #include <QWhatsThis>
0027 
0028 #include <KTextEditor/Document>
0029 #include <KTextEditor/Editor>
0030 #include <KTextEditor/View>
0031 
0032 static const char s_configFile[] = "kate-snippetsrc";
0033 
0034 KTextEditor::View *createView(QWidget *tabWidget)
0035 {
0036     auto document = KTextEditor::Editor::instance()->createDocument(tabWidget);
0037     auto view = document->createView(tabWidget);
0038 
0039     view->action(QStringLiteral("file_save"))->setEnabled(false);
0040     tabWidget->layout()->addWidget(view);
0041     view->setStatusBarEnabled(false);
0042     return view;
0043 }
0044 
0045 EditSnippet::EditSnippet(SnippetRepository *repository, Snippet *snippet, QWidget *parent)
0046     : QDialog(parent)
0047     , m_ui(std::make_unique<Ui::EditSnippetBase>())
0048     , m_repo(repository)
0049     , m_snippet(snippet)
0050     , m_topBoxModified(false)
0051 {
0052     Q_ASSERT(m_repo);
0053     m_ui->setupUi(this);
0054 
0055     connect(this, &QDialog::accepted, this, &EditSnippet::save);
0056 
0057     m_okButton = m_ui->buttons->button(QDialogButtonBox::Ok);
0058     KGuiItem::assign(m_okButton, KStandardGuiItem::ok());
0059     m_ui->buttons->addButton(m_okButton, QDialogButtonBox::AcceptRole);
0060     connect(m_okButton, &QPushButton::clicked, this, &QDialog::accept);
0061 
0062     auto cancelButton = m_ui->buttons->button(QDialogButtonBox::Cancel);
0063     KGuiItem::assign(cancelButton, KStandardGuiItem::cancel());
0064     m_ui->buttons->addButton(cancelButton, QDialogButtonBox::RejectRole);
0065     connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject);
0066 
0067     m_snippetView = createView(m_ui->snippetTab);
0068     if (!m_repo->fileTypes().isEmpty()) {
0069         m_snippetView->document()->setMode(m_repo->fileTypes().first());
0070     }
0071 
0072     m_scriptsView = createView(m_ui->scriptTab);
0073     m_scriptsView->document()->setMode(QStringLiteral("JavaScript"));
0074     m_scriptsView->document()->setText(m_repo->script());
0075     m_scriptsView->document()->setModified(false);
0076 
0077     // view for testing the snippet
0078     m_testView = createView(m_ui->testWidget);
0079     // splitter default size ratio
0080     m_ui->splitter->setSizes(QList<int>() << 400 << 150);
0081     connect(m_ui->dotest_button, &QPushButton::clicked, this, &EditSnippet::test);
0082 
0083     // modified notification stuff
0084     connect(m_ui->snippetNameEdit, &QLineEdit::textEdited, this, &EditSnippet::topBoxModified);
0085     connect(m_ui->snippetNameEdit, &QLineEdit::textEdited, this, &EditSnippet::validate);
0086     connect(m_ui->snippetShortcut, &KKeySequenceWidget::keySequenceChanged, this, &EditSnippet::topBoxModified);
0087     connect(m_snippetView->document(), &KTextEditor::Document::textChanged, this, &EditSnippet::validate);
0088 
0089     auto showHelp = [](const QString &text) {
0090         QWhatsThis::showText(QCursor::pos(), text);
0091     };
0092     connect(m_ui->snippetLabel, &QLabel::linkActivated, showHelp);
0093     connect(m_ui->scriptLabel, &QLabel::linkActivated, showHelp);
0094 
0095     // if we edit a snippet, add all existing data
0096     if (m_snippet) {
0097         setWindowTitle(i18n("Edit Snippet %1 in %2", m_snippet->text(), m_repo->text()));
0098 
0099         m_snippetView->document()->setText(m_snippet->snippet());
0100         m_ui->snippetNameEdit->setText(m_snippet->text());
0101         m_ui->snippetShortcut->setKeySequence(m_snippet->action()->shortcut());
0102 
0103         // unset modified flags
0104         m_snippetView->document()->setModified(false);
0105         m_topBoxModified = false;
0106     } else {
0107         setWindowTitle(i18n("Create New Snippet in Repository %1", m_repo->text()));
0108     }
0109 
0110     m_ui->messageWidget->hide();
0111     validate();
0112 
0113     m_ui->snippetNameEdit->setFocus();
0114     setTabOrder(m_ui->snippetNameEdit, m_snippetView);
0115 
0116     KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String(s_configFile));
0117     KConfigGroup group = config->group(QStringLiteral("General"));
0118     const QSize savedSize = group.readEntry("Size", QSize());
0119     if (savedSize.isValid()) {
0120         resize(savedSize);
0121     }
0122 }
0123 
0124 void EditSnippet::test()
0125 {
0126     m_testView->document()->clear();
0127     m_testView->insertTemplate(KTextEditor::Cursor(0, 0), m_snippetView->document()->text(), m_scriptsView->document()->text());
0128     m_testView->setFocus();
0129 }
0130 
0131 EditSnippet::~EditSnippet() = default;
0132 
0133 void EditSnippet::setSnippetText(const QString &text)
0134 {
0135     m_snippetView->document()->setText(text);
0136     validate();
0137 }
0138 
0139 void EditSnippet::validate()
0140 {
0141     const QString &name = m_ui->snippetNameEdit->text();
0142     bool valid = !name.isEmpty() && !m_snippetView->document()->isEmpty();
0143     // make sure the snippetname includes no spaces
0144     if (name.contains(QLatin1Char(' ')) || name.contains(QLatin1Char('\t'))) {
0145         m_ui->messageWidget->setText(i18n("Snippet name cannot contain spaces"));
0146         m_ui->messageWidget->animatedShow();
0147         valid = false;
0148     } else {
0149         // hide message widget if snippet does not include spaces
0150         m_ui->messageWidget->animatedHide();
0151     }
0152     if (valid) {
0153         m_ui->messageWidget->hide();
0154     }
0155     m_okButton->setEnabled(valid);
0156 }
0157 
0158 void EditSnippet::save()
0159 {
0160     Q_ASSERT(!m_ui->snippetNameEdit->text().isEmpty());
0161 
0162     if (!m_snippet) {
0163         // save as new snippet
0164         m_snippet = new Snippet();
0165         m_snippet->action(); // ensure that the snippet's QAction is created before it is added to a widget by the rowsInserted() signal
0166         m_repo->appendRow(m_snippet);
0167     }
0168     m_snippet->setSnippet(m_snippetView->document()->text());
0169     m_snippetView->document()->setModified(false);
0170     m_snippet->setText(m_ui->snippetNameEdit->text());
0171     m_snippet->action()->setShortcut(m_ui->snippetShortcut->keySequence());
0172     m_repo->setScript(m_scriptsView->document()->text());
0173     m_scriptsView->document()->setModified(false);
0174     m_topBoxModified = false;
0175     m_repo->save();
0176 
0177     setWindowTitle(i18n("Edit Snippet %1 in %2", m_snippet->text(), m_repo->text()));
0178 
0179     KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String(s_configFile));
0180     KConfigGroup group = config->group(QStringLiteral("General"));
0181     group.writeEntry("Size", size());
0182     group.sync();
0183 }
0184 
0185 void EditSnippet::reject()
0186 {
0187     if (m_topBoxModified || m_snippetView->document()->isModified() || m_scriptsView->document()->isModified()) {
0188         int ret = KMessageBox::warningContinueCancel(qApp->activeWindow(),
0189                                                      i18n("The snippet contains unsaved changes. Do you want to continue and lose all changes?"),
0190                                                      i18n("Warning - Unsaved Changes"));
0191         if (ret == KMessageBox::Cancel) {
0192             return;
0193         }
0194     }
0195     QDialog::reject();
0196 }
0197 
0198 void EditSnippet::topBoxModified()
0199 {
0200     m_topBoxModified = true;
0201 }
0202 
0203 #include "moc_editsnippet.cpp"