File indexing completed on 2024-05-12 04:37:46

0001 /*
0002     SPDX-FileCopyrightText: 2008 Aleix Pol <aleixpol@gmail.com>
0003     SPDX-FileCopyrightText: 2009 Ramón Zarazúa <killerfox512+kde@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "applychangeswidget.h"
0009 
0010 #include <KTextEditor/Document>
0011 
0012 #include <KParts/PartLoader>
0013 #include <KParts/ReadWritePart>
0014 
0015 #include <QAction>
0016 #include <QDialogButtonBox>
0017 #include <QDir>
0018 #include <QLabel>
0019 #include <QMimeType>
0020 #include <QMimeDatabase>
0021 #include <QPushButton>
0022 #include <QSplitter>
0023 #include <QTemporaryFile>
0024 #include <QTabWidget>
0025 #include <QVBoxLayout>
0026 
0027 #include "coderepresentation.h"
0028 #include <interfaces/icore.h>
0029 #include <interfaces/idocumentcontroller.h>
0030 
0031 namespace KDevelop {
0032 class ApplyChangesWidgetPrivate
0033 {
0034 public:
0035 
0036     explicit ApplyChangesWidgetPrivate(ApplyChangesWidget* p)
0037         : parent(p)
0038         , m_index(0) {}
0039     ~ApplyChangesWidgetPrivate()
0040     {
0041         qDeleteAll(m_temps);
0042     }
0043 
0044     void createEditPart(const KDevelop::IndexedString& url);
0045 
0046     ApplyChangesWidget* const parent;
0047     int m_index;
0048     QList<KParts::ReadWritePart*> m_editParts;
0049     QList<QTemporaryFile*> m_temps;
0050     QList<IndexedString> m_files;
0051     QTabWidget* m_documentTabs;
0052     QLabel* m_info;
0053 };
0054 
0055 ApplyChangesWidget::ApplyChangesWidget(QWidget* parent)
0056     : QDialog(parent)
0057     , d_ptr(new ApplyChangesWidgetPrivate(this))
0058 {
0059     Q_D(ApplyChangesWidget);
0060 
0061     setSizeGripEnabled(true);
0062 
0063     auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0064     auto mainLayout = new QVBoxLayout(this);
0065     auto okButton = buttonBox->button(QDialogButtonBox::Ok);
0066     okButton->setDefault(true);
0067     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0068     connect(buttonBox, &QDialogButtonBox::accepted, this, &ApplyChangesWidget::accept);
0069     connect(buttonBox, &QDialogButtonBox::rejected, this, &ApplyChangesWidget::reject);
0070 
0071     auto* w = new QWidget(this);
0072     d->m_info = new QLabel(w);
0073     d->m_documentTabs = new QTabWidget(w);
0074     connect(d->m_documentTabs, &QTabWidget::currentChanged,
0075             this, &ApplyChangesWidget::indexChanged);
0076 
0077     auto* l = new QVBoxLayout(w);
0078     l->addWidget(d->m_info);
0079     l->addWidget(d->m_documentTabs);
0080 
0081     mainLayout->addWidget(w);
0082     mainLayout->addWidget(buttonBox);
0083 
0084     resize(QSize(800, 400));
0085 }
0086 
0087 ApplyChangesWidget::~ApplyChangesWidget() = default;
0088 
0089 bool ApplyChangesWidget::hasDocuments() const
0090 {
0091     Q_D(const ApplyChangesWidget);
0092 
0093     return d->m_editParts.size() > 0;
0094 }
0095 
0096 KTextEditor::Document* ApplyChangesWidget::document() const
0097 {
0098     Q_D(const ApplyChangesWidget);
0099 
0100     return qobject_cast<KTextEditor::Document*>(d->m_editParts.value(d->m_index));
0101 }
0102 
0103 void ApplyChangesWidget::setInformation(const QString& info)
0104 {
0105     Q_D(ApplyChangesWidget);
0106 
0107     d->m_info->setText(info);
0108 }
0109 
0110 void ApplyChangesWidget::addDocuments(const IndexedString& original)
0111 {
0112     Q_D(ApplyChangesWidget);
0113 
0114     int idx = d->m_files.indexOf(original);
0115     if (idx < 0) {
0116         auto* w = new QWidget;
0117         d->m_documentTabs->addTab(w, original.str());
0118         d->m_documentTabs->setCurrentWidget(w);
0119 
0120         d->m_files.insert(d->m_index, original);
0121         d->createEditPart(original);
0122     } else {
0123         d->m_index = idx;
0124     }
0125 }
0126 
0127 bool ApplyChangesWidget::applyAllChanges()
0128 {
0129     Q_D(ApplyChangesWidget);
0130 
0131     /// @todo implement safeguard in case a file saving fails
0132 
0133     bool ret = true;
0134     for (int i = 0; i < d->m_files.size(); ++i)
0135         if (d->m_editParts[i]->saveAs(d->m_files[i].toUrl())) {
0136             IDocument* doc = ICore::self()->documentController()->documentForUrl(d->m_files[i].toUrl());
0137             if (doc && doc->state() == IDocument::Dirty)
0138                 doc->reload();
0139         } else
0140             ret = false;
0141 
0142     return ret;
0143 }
0144 }
0145 
0146 namespace KDevelop {
0147 void ApplyChangesWidgetPrivate::createEditPart(const IndexedString& file)
0148 {
0149     QWidget* widget = m_documentTabs->currentWidget();
0150     Q_ASSERT(widget);
0151 
0152     auto* m = new QVBoxLayout(widget);
0153     auto* v = new QSplitter(widget);
0154     m->addWidget(v);
0155 
0156     QUrl url = file.toUrl();
0157 
0158     QMimeType mimetype = QMimeDatabase().mimeTypeForUrl(url);
0159 
0160     auto* part =
0161         KParts::PartLoader::createPartInstanceForMimeType<KParts::ReadWritePart>(mimetype.name(), widget, widget);
0162     auto* document = qobject_cast<KTextEditor::Document*>(part);
0163     Q_ASSERT(document);
0164 
0165     Q_ASSERT(document->action("file_save"));
0166     document->action("file_save")->setEnabled(false);
0167 
0168     m_editParts.insert(m_index, part);
0169 
0170     //Open the best code representation, even if it is artificial
0171     CodeRepresentation::Ptr repr = createCodeRepresentation(file);
0172     if (!repr->fileExists()) {
0173         const QString templateName = QDir::tempPath() + QLatin1Char('/') +
0174                                      url.fileName().split(QLatin1Char('.')).last();
0175         auto* temp(new QTemporaryFile(templateName));
0176         temp->open();
0177         temp->write(repr->text().toUtf8());
0178         temp->close();
0179 
0180         url = QUrl::fromLocalFile(temp->fileName());
0181 
0182         m_temps << temp;
0183     }
0184     m_editParts[m_index]->openUrl(url);
0185 
0186     v->addWidget(m_editParts[m_index]->widget());
0187     v->setSizes(QList<int> {400, 100});
0188 }
0189 
0190 void ApplyChangesWidget::indexChanged(int newIndex)
0191 {
0192     Q_D(ApplyChangesWidget);
0193 
0194     Q_ASSERT(newIndex != -1);
0195     d->m_index = newIndex;
0196 }
0197 
0198 void ApplyChangesWidget::updateDiffView(int index)
0199 {
0200     Q_D(ApplyChangesWidget);
0201 
0202     d->m_index = index == -1 ? d->m_index : index;
0203 }
0204 }
0205 
0206 #include "moc_applychangeswidget.cpp"