File indexing completed on 2024-05-19 12:55:53
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