File indexing completed on 2024-04-21 15:24:34

0001 /*
0002     SPDX-FileCopyrightText: 2013 Sven Brauch <svenbrauch@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005 */
0006 
0007 #include "docfilemanagerwidget.h"
0008 #include "kcm_docfiles.h"
0009 #include "docfilewizard.h"
0010 #include <interfaces/idocumentcontroller.h>
0011 #include <interfaces/icore.h>
0012 
0013 #include <QBoxLayout>
0014 #include <QFileSystemModel>
0015 #include <QDialogButtonBox>
0016 #include <QTreeView>
0017 #include <QPushButton>
0018 #include <QSplitter>
0019 #include <QLabel>
0020 #include <QTextEdit>
0021 #include <QUrl>
0022 #include <QDebug>
0023 #include <QTemporaryFile>
0024 #include <QStandardPaths>
0025 #include <QDesktopServices>
0026 #include <QIcon>
0027 
0028 #include <KMessageBox>
0029 #include <KLocalizedString>
0030 #include <KTextEditor/Document>
0031 
0032 DocfileManagerWidget::DocfileManagerWidget(QWidget* parent)
0033     : QWidget(parent)
0034 {
0035     QString dir = docfilePath();
0036     if ( dir.isEmpty() ) {
0037         KMessageBox::error(this, i18n("Failed to find a valid data directory for kdevpythonsupport."));
0038         return;
0039     }
0040 
0041     // construct the tree view which displays the currently installed files
0042     QFileSystemModel* model = new QFileSystemModel(this);
0043     model->setRootPath(dir);
0044     filesTreeView = new QTreeView;
0045     filesTreeView->setSelectionMode(QAbstractItemView::MultiSelection);
0046     filesTreeView->setModel(model);
0047     filesTreeView->setRootIndex(model->index(dir));
0048 
0049     // construct the buttons for up/download
0050     QVBoxLayout* buttonsLayout = new QVBoxLayout;
0051     QPushButton* generateButton = new QPushButton(i18n("Generate..."));
0052     generateButton->setIcon(QIcon::fromTheme("tools-wizard"));
0053     QPushButton* importButton = new QPushButton(i18n("Import From Editor"));
0054     importButton->setToolTip(i18n("Copy the contents of the active editor window "
0055                                   "to a new file in the documentation directory"));
0056     buttonsLayout->addWidget(generateButton);
0057     buttonsLayout->addWidget(importButton);
0058     QObject::connect(generateButton, &QAbstractButton::clicked, this, &DocfileManagerWidget::runWizard);
0059     QObject::connect(importButton, &QAbstractButton::clicked, this, &DocfileManagerWidget::copyEditorContents);
0060 
0061     // construct the buttons for the remaining actions
0062     QFrame* separator = new QFrame();
0063     separator->setFrameShape(QFrame::HLine);
0064     QFrame* separator2 = new QFrame();
0065     separator2->setFrameShape(QFrame::HLine);
0066     QPushButton* openFileManagerButton = new QPushButton(i18n("Open File Manager"));
0067     openFileManagerButton->setIcon(QIcon::fromTheme(QStringLiteral("system-file-manager")));
0068     QPushButton* openTextEditorButton = new QPushButton(i18nc("Edit selected files", "Edit Selected"));
0069     openTextEditorButton->setIcon(QIcon::fromTheme(QStringLiteral("document-edit")));
0070     QPushButton* searchPathsButton = new QPushButton(i18n("Search Paths..."));
0071     searchPathsButton->setIcon(QIcon::fromTheme(QStringLiteral("search")));
0072     buttonsLayout->addWidget(separator);
0073     buttonsLayout->addWidget(openFileManagerButton);
0074     buttonsLayout->addWidget(openTextEditorButton);
0075     buttonsLayout->addWidget(separator2);
0076     buttonsLayout->addWidget(searchPathsButton);
0077     QObject::connect(openFileManagerButton, &QAbstractButton::clicked, this, &DocfileManagerWidget::openDocfilePath);
0078     QObject::connect(openTextEditorButton, &QAbstractButton::clicked, this, &DocfileManagerWidget::openSelectedInTextEditor);
0079     QObject::connect(searchPathsButton, &QAbstractButton::clicked, this, &DocfileManagerWidget::showSearchPaths);
0080 
0081     buttonsLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding));
0082 
0083     // arrange the results nicely around a splitter
0084     QSplitter* splitter = new QSplitter;
0085     QWidget* w = new QWidget;
0086     w->setLayout(buttonsLayout);
0087     splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0088     splitter->addWidget(filesTreeView);
0089     splitter->addWidget(w);
0090     splitter->setSizes(QList<int>() << 800 << 100);
0091 
0092     setLayout(new QVBoxLayout);
0093     layout()->addWidget(splitter);
0094     layout()->setContentsMargins(0, 0, 0, 0);
0095 }
0096 
0097 void DocfileManagerWidget::showSearchPaths()
0098 {
0099     QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kdevpythonsupport/documentation_files", QStandardPaths::LocateDirectory);
0100     QLabel* dirsMessageLabel = new QLabel(i18nc("displays a list of search paths below",
0101                                                 "Paths searched for documentation by kdev-python (in this order):"));
0102     QTextEdit* paths = new QTextEdit;
0103     paths->setPlainText(dirs.join("\n"));
0104     paths->setReadOnly(true);
0105 
0106     QDialog* message = new QDialog(this);
0107     message->setLayout(new QVBoxLayout);
0108     message->layout()->addWidget(dirsMessageLabel);
0109     message->layout()->addWidget(paths);
0110     QWidget* closeWidget = new QWidget;
0111     QPushButton* closeButton = new QPushButton("Close");
0112     closeWidget->setLayout(new QHBoxLayout);
0113     closeWidget->layout()->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding));
0114     closeWidget->layout()->addWidget(closeButton);
0115     message->layout()->addWidget(closeWidget);
0116 
0117     QObject::connect(closeButton, &QAbstractButton::clicked, message, &QWidget::close);
0118     message->resize(600, 200);
0119     message->exec();
0120 }
0121 
0122 void DocfileManagerWidget::openDocfilePath()
0123 {
0124     if ( QDir(docfilePath()).exists() ) {
0125         QDesktopServices::openUrl(QUrl::fromLocalFile(docfilePath()));
0126     }
0127 }
0128 
0129 void DocfileManagerWidget::copyEditorContents()
0130 {
0131     KDevelop::IDocumentController* documentController = KDevelop::ICore::self()->documentController();
0132     if ( documentController->activeDocument() ) {
0133         if ( KTextEditor::Document* doc = documentController->activeDocument()->textDocument() ) {
0134             auto dialog = new QDialog(this);
0135             auto buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);
0136             connect(buttonbox->button(QDialogButtonBox::Ok), &QPushButton::clicked,
0137                     dialog, &QDialog::accept);
0138             connect(buttonbox->button(QDialogButtonBox::Cancel), &QPushButton::clicked,
0139                     dialog, &QDialog::reject);
0140             dialog->setLayout(new QVBoxLayout);
0141             dialog->layout()->addWidget(new QLabel(i18n("Enter a relative target path to copy %1 to:", doc->url().path())));
0142             QLineEdit* lineEdit = new QLineEdit;
0143             lineEdit->setText(doc->documentName());
0144             dialog->layout()->addWidget(lineEdit);
0145             dialog->layout()->addWidget(new QLabel(i18n("This path must match what you use in Python to import "
0146                                                           "this module. For example, enter \"numpy/fft.py\" for numpy.fft")));
0147             dialog->layout()->addWidget(new QLabel(i18n("After copying, you will be editing the new document.")));
0148             dialog->layout()->addWidget(buttonbox);
0149             if ( dialog->exec() == QDialog::Accepted ) {
0150                 auto target = QUrl::fromLocalFile(docfilePath() + "/" + lineEdit->text());
0151                 // TODO QUrl: cleanPath?
0152                 QDir d(target.url());
0153                 if ( ! d.exists() ) {
0154                     d.mkpath(d.absolutePath());
0155                 }
0156                 doc->saveAs(target);
0157             }
0158         }
0159     }
0160 }
0161 
0162 void DocfileManagerWidget::openSelectedInTextEditor()
0163 {
0164     const QList<QUrl> selected = selectedItems();
0165     if ( selected.isEmpty() ) {
0166         KMessageBox::information(this, i18n("Please select at least one file from the list for editing."));
0167     }
0168     foreach ( const QUrl& item, selected ) {
0169         KDevelop::ICore::self()->documentController()->openDocument(item);
0170     }
0171 }
0172 
0173 QString DocfileManagerWidget::docfilePath()
0174 {
0175     // finds a local directory which is contained in the dirs searched by the parser, code
0176     // and creates it if it doesn't exist
0177     QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/" + "kdevpythonsupport/documentation_files/";
0178     QDir dir(path);
0179     dir.mkpath(path);
0180     return path;
0181 }
0182 
0183 const QList<QUrl> DocfileManagerWidget::selectedItems() const
0184 {
0185     const QModelIndexList items = filesTreeView->selectionModel()->selectedRows();
0186     QList<QUrl> urls;
0187     const QFileSystemModel* fsmodel = qobject_cast<QFileSystemModel*>(filesTreeView->model());
0188     foreach ( const QModelIndex& index, items ) {
0189         urls << QUrl::fromLocalFile(fsmodel->filePath(index));
0190     }
0191     return urls;
0192 }
0193 
0194 void DocfileManagerWidget::runWizard()
0195 {
0196     DocfileWizard wizard(docfilePath(), this);
0197     wizard.exec();
0198 }
0199 
0200 #include "moc_docfilemanagerwidget.cpp"