File indexing completed on 2024-05-05 17:15:11

0001 /******************************************************************************************
0002     begin                : Fri Aug 15 2003
0003     copyright            : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)
0004                            (C) 2007 by Holger Danielsson (holger.danielsson@versanet.de)
0005                            (C) 2011 by Libor Bukata (lbukata@gmail.com)
0006                            (C) 2013 by Michel Ludwig (michel.ludwig@kdemail.net)
0007  ******************************************************************************************/
0008 
0009 /***************************************************************************
0010  *                                                                         *
0011  *   This program is free software; you can redistribute it and/or modify  *
0012  *   it under the terms of the GNU General Public License as published by  *
0013  *   the Free Software Foundation; either version 2 of the License, or     *
0014  *   (at your option) any later version.                                   *
0015  *                                                                         *
0016  ***************************************************************************/
0017 
0018 #include "listselector.h"
0019 
0020 #include <algorithm>
0021 
0022 #include <QApplication>
0023 #include <QDir>
0024 #include <QFile>
0025 #include <QFileInfo>
0026 #include <QLabel>
0027 #include <QLayout>
0028 #include <QList>
0029 #include <QStringList>
0030 #include <QTreeWidget>
0031 #include <QVBoxLayout>
0032 #include <QDialogButtonBox>
0033 #include <QPushButton>
0034 #include <QFileDialog>
0035 
0036 #include <KDirWatch>
0037 #include <KLocalizedString>
0038 #include <KMessageBox>
0039 #include <KRun>
0040 
0041 #include "kiledebug.h"
0042 #include "codecompletion.h"
0043 
0044 //////////////////// KileListSelector ////////////////////
0045 
0046 KileListSelector::KileListSelector(const QStringList &list, const QString &caption, const QString &select, bool sort,
0047                                    QWidget *parent, const char *name)
0048     : QDialog(parent)
0049     , m_listView(new QTreeWidget(this))
0050     , m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel))
0051 {
0052     setObjectName(name);
0053     setWindowTitle(caption);
0054     setModal(true);
0055     QVBoxLayout *mainLayout = new QVBoxLayout;
0056     setLayout(mainLayout);
0057     mainLayout->addWidget(new QLabel(select, this));
0058 
0059     m_listView->setHeaderLabel(i18n("Files"));
0060     m_listView->setSortingEnabled(false);
0061     m_listView->setAllColumnsShowFocus(true);
0062     m_listView->setRootIsDecorated(false);
0063     mainLayout->addWidget(m_listView);
0064     mainLayout->addWidget(new QLabel(i18np("1 item found.", "%1 items found.", list.size())));
0065 
0066     m_listView->setSortingEnabled(sort);
0067     m_listView->setSelectionMode(QAbstractItemView::SingleSelection);
0068     if (sort) {
0069         m_listView->sortByColumn(0, Qt::AscendingOrder);
0070     }
0071 
0072     insertStringList(list);
0073 
0074     m_listView->clearSelection();
0075     connect(m_listView, &QTreeWidget::itemDoubleClicked, this, &QDialog::accept);
0076     QItemSelectionModel *selectionModel = m_listView->selectionModel();
0077     if (selectionModel) { // checking just to be safe
0078         connect(selectionModel, &QItemSelectionModel::selectionChanged,
0079                 this, &KileListSelector::handleSelectionChanged);
0080     }
0081 
0082     QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok);
0083     okButton->setDefault(true);
0084     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0085     okButton->setEnabled(false);
0086     connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0087     connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0088     mainLayout->addWidget(m_buttonBox);
0089 }
0090 
0091 void KileListSelector::handleSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
0092 {
0093     Q_UNUSED(selected);
0094     Q_UNUSED(deselected);
0095     m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(hasSelection());
0096 }
0097 
0098 bool KileListSelector::hasSelection() const
0099 {
0100     if (!m_listView->selectionModel()) {
0101         return false;
0102     }
0103     return m_listView->selectionModel()->hasSelection();
0104 }
0105 
0106 void KileListSelector::setSelectionMode(QAbstractItemView::SelectionMode mode)
0107 {
0108     m_listView->setSelectionMode(mode);
0109 }
0110 
0111 void KileListSelector::insertStringList(const QStringList &list)
0112 {
0113     QStringList::ConstIterator it;
0114     for (it = list.begin(); it != list.end(); ++it) {
0115         QTreeWidgetItem *item = new QTreeWidgetItem(m_listView, QStringList(*it));
0116 
0117         if (it == list.begin()) {
0118             m_listView->setCurrentItem(item);
0119         }
0120     }
0121 }
0122 
0123 QStringList KileListSelector::selectedItems() const
0124 {
0125     QStringList items;
0126     QTreeWidgetItemIterator it(m_listView, QTreeWidgetItemIterator::Selected);
0127     while (*it) {
0128         items.append((*it)->text(0));
0129         ++it;
0130     }
0131     return items;
0132 }
0133 
0134 
0135 //////////////////// ManageCompletionFilesDialog ////////////////////
0136 
0137 ManageCompletionFilesDialog::ManageCompletionFilesDialog(const QString& caption,
0138         const QString &localCompletionDir, const QString &globalCompletionDir, QWidget* parent, const char* name)
0139     : QDialog(parent)
0140     , m_localCompletionDirectory(localCompletionDir)
0141     , m_globalCompletionDirectory(globalCompletionDir)
0142 {
0143     setObjectName(name);
0144     setWindowTitle(caption);
0145     setModal(true);
0146     QVBoxLayout *mainLayout = new QVBoxLayout;
0147     setLayout(mainLayout);
0148 
0149     m_listView = new QTreeWidget(this);
0150     m_listView->setHeaderLabels(QStringList() << i18n("File Name") << i18n("Local File") << i18n("Add File?"));
0151     m_listView->setSortingEnabled(false);
0152     m_listView->setSelectionMode(QAbstractItemView::NoSelection);
0153     m_listView->setRootIsDecorated(false);
0154     mainLayout->addWidget(m_listView);
0155 
0156     m_dirWatcher = new KDirWatch(this);
0157     if (m_dirWatcher) {
0158         m_dirWatcher->addDir(localCompletionDir, KDirWatch::WatchFiles);
0159         connect(m_dirWatcher, &KDirWatch::created, this, &ManageCompletionFilesDialog::fillTreeView);
0160         connect(m_dirWatcher, &KDirWatch::deleted, this, &ManageCompletionFilesDialog::fillTreeView);
0161     }
0162     fillTreeView();
0163 
0164     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
0165     QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
0166     QPushButton *installCustomButton = new QPushButton;
0167     QPushButton *manageCustomButton = new QPushButton;
0168     okButton->setDefault(true);
0169     okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
0170     okButton->setText(i18n("Add selected files"));
0171     okButton->setToolTip(i18n("Add all the selected files"));
0172     installCustomButton->setText(i18n("Install custom files"));
0173     installCustomButton->setToolTip(i18n("Install your own completion files"));
0174     manageCustomButton->setText(i18n("Manage custom files"));
0175     manageCustomButton->setToolTip(i18n("Manage the local completion files in the file manager"));
0176     buttonBox->addButton(installCustomButton, QDialogButtonBox::ActionRole);
0177     buttonBox->addButton(manageCustomButton, QDialogButtonBox::ActionRole);
0178     mainLayout->addWidget(buttonBox);
0179     connect(buttonBox, &QDialogButtonBox::accepted,
0180             this, &QDialog::accept);
0181     connect(buttonBox, &QDialogButtonBox::rejected,
0182             this, &QDialog::reject);
0183     connect(installCustomButton, &QPushButton::clicked,
0184             this, &ManageCompletionFilesDialog::addCustomCompletionFiles);
0185     connect(manageCustomButton, &QPushButton::clicked,
0186             this, &ManageCompletionFilesDialog::openLocalCompletionDirectoryInFileManager);
0187 
0188     // Create the local path if it doesn't exist
0189     QDir localPath(m_localCompletionDirectory);
0190     if(!localPath.exists()) {
0191         localPath.mkpath(m_localCompletionDirectory);
0192     }
0193 }
0194 
0195 ManageCompletionFilesDialog::~ManageCompletionFilesDialog()
0196 {
0197 }
0198 
0199 void ManageCompletionFilesDialog::fillTreeView() {
0200     // we want to keep selected items still selected after refreshing
0201     QSet<QString> previouslySelectedItems = selected();
0202     QStringList list = KileCodeCompletion::Manager::getAllCwlFiles(m_localCompletionDirectory, m_globalCompletionDirectory).values();
0203     std::sort(list.begin(), list.end());
0204     m_listView->clear();
0205     foreach(QString filename, list) {
0206         QString expectedLocalPath = m_localCompletionDirectory + '/' + filename;
0207         QString expectedGlobalPath = m_globalCompletionDirectory + '/' + filename;
0208         if (QFileInfo::exists(expectedLocalPath) && QFileInfo(expectedLocalPath).isReadable()) {
0209             QTreeWidgetItem* item = new QTreeWidgetItem(m_listView, QStringList() << filename << i18n("yes"));
0210             item->setCheckState(2, previouslySelectedItems.contains(filename) ? Qt::Checked : Qt::Unchecked);
0211         }
0212         else if (QFileInfo::exists(expectedGlobalPath) && QFileInfo(expectedGlobalPath).isReadable()) {
0213             QTreeWidgetItem* item = new QTreeWidgetItem(m_listView, QStringList() << filename << i18n("no"));
0214             item->setCheckState(2, previouslySelectedItems.contains(filename) ? Qt::Checked : Qt::Unchecked);
0215         }
0216         else {
0217             KILE_DEBUG_MAIN << "Cannot load file" << filename << "!";
0218         }
0219     }
0220     m_listView->resizeColumnToContents(0);
0221     m_listView->resizeColumnToContents(1);
0222     m_listView->resizeColumnToContents(2);
0223 }
0224 
0225 void ManageCompletionFilesDialog::addCustomCompletionFiles()
0226 {
0227     bool someFileAdded = false;
0228     QStringList files = QFileDialog::getOpenFileNames(
0229                             this, i18n("Select Completion Files to Install Locally"), QString(), i18n("Completion files (*.cwl)"));
0230 
0231     if (files.isEmpty()) {
0232         return;
0233     }
0234     QDir workPath(m_localCompletionDirectory);
0235 
0236     foreach (QString file, files) {
0237         QFileInfo fileInf(file);
0238         QFileInfo localFile(m_localCompletionDirectory + '/' + fileInf.fileName());
0239         if (localFile.exists()) {
0240             const QString dialog_text = i18n("A local completion file with the name \"%1\" already exists.\nDo you want to replace this file?", localFile.fileName());
0241             const QString dialog_caption = i18n("Replace Local File?");
0242             if (KMessageBox::questionTwoActions(this, dialog_text, dialog_caption, KStandardGuiItem::ok(), KStandardGuiItem::cancel()) == KMessageBox::PrimaryAction) {
0243                 if (!QFile::remove(localFile.absoluteFilePath())) {
0244                     KMessageBox::error(this, i18n("An error occurred while removing the file \"%1\".\nPlease check the file permissions.",
0245                                        localFile.fileName()), i18n("Remove Error"));
0246                     continue;
0247                 }
0248             }
0249             else {
0250                 // Skip selected file.
0251                 continue;
0252             }
0253         }
0254         // Copy selected file to local directory.
0255         if (!QFile::copy(fileInf.absoluteFilePath(),localFile.absoluteFilePath())) {
0256             KMessageBox::error(this, i18n("Cannot copy the file to the local directory!\nPlease check the access permissions of the directory \"%1\".",
0257                                localFile.absolutePath()), i18n("Copy Error"));
0258         }
0259         else {
0260             // Add file to QTreeWidget or change status to local if a global file with the same name exists.
0261             QList<QTreeWidgetItem*> foundItems = m_listView->findItems(fileInf.fileName(), Qt::MatchExactly, 0);
0262             if (foundItems.empty()) {
0263                 QTreeWidgetItem *item = new QTreeWidgetItem(m_listView, QStringList() << localFile.fileName() << i18n("yes"));
0264                 item->setCheckState(2, Qt::Checked);
0265             }
0266             else {
0267                 foundItems.first()->setCheckState(2, Qt::Checked);
0268                 foundItems.first()->setText(1, i18n("yes"));
0269             }
0270             someFileAdded = true;
0271         }
0272     }
0273 
0274     // Resort QTreeWidget list.
0275     m_listView->sortItems(0, Qt::AscendingOrder);
0276 
0277     // Info about preselected files.
0278     if (someFileAdded == true) {
0279         KMessageBox::information(this,
0280                                  i18n("The custom files have been installed and preselected for adding."),
0281                                  i18n("Installation Successful"));
0282     }
0283 }
0284 
0285 void ManageCompletionFilesDialog::openLocalCompletionDirectoryInFileManager()
0286 {
0287     new KRun(QUrl::fromLocalFile(m_localCompletionDirectory), QApplication::activeWindow());
0288 }
0289 
0290 const QSet<QString> ManageCompletionFilesDialog::selected() const
0291 {
0292     QSet<QString> checked_files;
0293     for (int i = 0; i < m_listView->topLevelItemCount(); ++i) {
0294         QTreeWidgetItem* item = m_listView->topLevelItem(i);
0295         if (item->checkState(2) == Qt::Checked) {
0296             checked_files.insert(item->text(0));
0297         }
0298     }
0299 
0300     return checked_files;
0301 }
0302