File indexing completed on 2024-05-12 09:06:24
0001 /************************************************************************************************ 0002 Copyright (C) 2004-2007 by Holger Danielsson (holger.danielsson@versanet.de) 0003 2009-2010 by Michel Ludwig (michel.ludwig@kdemail.net) 0004 ************************************************************************************************/ 0005 0006 0007 /*************************************************************************** 0008 * * 0009 * This program is free software; you can redistribute it and/or modify * 0010 * it under the terms of the GNU General Public License as published by * 0011 * the Free Software Foundation; either version 2 of the License, or * 0012 * (at your option) any later version. * 0013 * * 0014 ***************************************************************************/ 0015 0016 #include "widgets/codecompletionconfigwidget.h" 0017 0018 #include <QCheckBox> 0019 #include <QDir> 0020 #include <QFileInfo> 0021 #include <QGridLayout> 0022 #include <QGroupBox> 0023 #include <QLabel> 0024 #include <QLayout> 0025 #include <QSpinBox> 0026 #include <QStringList> 0027 #include <QTabWidget> 0028 #include <QTreeWidget> 0029 #include <QVBoxLayout> 0030 0031 #include <KConfig> 0032 #include <QDialog> 0033 #include <KDirWatch> 0034 #include <KLocalizedString> 0035 #include <KMessageBox> 0036 #include <QPushButton> 0037 #include <KConfigGroup> 0038 0039 #include "dialogs/listselector.h" 0040 #include "codecompletion.h" 0041 #include "errorhandler.h" 0042 #include "kileconfig.h" 0043 #include "kiledebug.h" 0044 #include "kiletool_enums.h" 0045 0046 CodeCompletionConfigWidget::CodeCompletionConfigWidget(KConfig *config, KileErrorHandler *errorHandler, QWidget *parent, const char *name) 0047 : QWidget(parent), m_config(config), m_errorHandler(errorHandler), m_configChanged(false) 0048 { 0049 setObjectName(name); 0050 setupUi(this); 0051 0052 // add three pages: Tex/Latex, Dictionary, Abbreviation 0053 addPage(m_tabWidget, TexPage, i18n("TeX/LaTeX"), "tex"); 0054 addPage(m_tabWidget, DictionaryPage, i18n("Dictionary"), "dictionary"); 0055 addPage(m_tabWidget, AbbreviationPage, i18n("Abbreviation"), "abbreviation"); 0056 0057 cb_setcursor->setWhatsThis(i18n("Try to place the cursor.")); 0058 cb_setbullets->setWhatsThis(i18n("Insert bullets where the user must input data.")); 0059 cb_closeenv->setWhatsThis(i18n("Also close an environment when an opening command is inserted.")); 0060 cb_autocomplete->setWhatsThis(i18n("Directional or popup-based completion of the TeX/LaTeX commands that are contained in the selected completion files.")); 0061 sp_latexthreshold->setWhatsThis(i18n("Automatically show a completion list of TeX/LaTeX commands when the word has this length.")); 0062 0063 cb_showabbrevview->setWhatsThis(i18n("Show abbreviations of the selected completion files in the sidebar")); 0064 cb_autocompleteabbrev->setWhatsThis(i18n("Directional or popup-based completion of abbreviations that are contained in the selected completion files.")); 0065 cb_showcwlview->setWhatsThis(i18n("Show LaTeX commands of the selected completion files in the sidebar")); 0066 0067 connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(showPage(int))); 0068 connect(m_addFileButton, SIGNAL(clicked()), this, SLOT(addClicked())); 0069 connect(m_removeFileButton, SIGNAL(clicked()), this, SLOT(removeClicked())); 0070 0071 // find resource directories for cwl files 0072 QPair<QString, QString> p = KileCodeCompletion::Manager::getCwlBaseDirs(); 0073 m_localCwlDir = p.first; 0074 m_globalCwlDir = p.second; 0075 0076 // Watch for changes in the directories 0077 m_dirWatcher = new KDirWatch(this); 0078 if (m_dirWatcher) { 0079 m_dirWatcher->addDir(m_localCwlDir, KDirWatch::WatchSubDirs | KDirWatch::WatchFiles); 0080 m_dirWatcher->addDir(m_globalCwlDir, KDirWatch::WatchSubDirs | KDirWatch::WatchFiles); 0081 connect(m_dirWatcher, SIGNAL(created(QString)), this, SLOT(updateCompletionFilesTab(QString))); 0082 connect(m_dirWatcher, SIGNAL(deleted(QString)), this, SLOT(updateCompletionFilesTab(QString))); 0083 } 0084 } 0085 0086 CodeCompletionConfigWidget::~CodeCompletionConfigWidget() 0087 { 0088 } 0089 0090 void CodeCompletionConfigWidget::addPage(QTabWidget *tab, CompletionPage page, const QString &title, const QString &dirname) 0091 { 0092 m_page[page] = new QWidget(tab); 0093 0094 m_listview[page] = new QTreeWidget(m_page[page]); 0095 m_listview[page]->setHeaderLabels(QStringList() << i18n("Completion Files") 0096 << i18n("Local File")); 0097 m_listview[page]->setAllColumnsShowFocus(true); 0098 m_listview[page]->setRootIsDecorated(false); 0099 m_listview[page]->setSelectionMode(QAbstractItemView::ExtendedSelection); 0100 0101 QGridLayout *grid = new QGridLayout(); 0102 grid->setContentsMargins(0, 0, 0, 0); 0103 //TODO PORT QT5 grid->setSpacing(QDialog::spacingHint()); 0104 m_page[page]->setLayout(grid); 0105 grid->addWidget(m_listview[page], 0, 0); 0106 0107 // add Tab 0108 tab->addTab(m_page[page], title); 0109 0110 // remember directory name 0111 m_dirname << dirname; 0112 0113 connect(m_listview[page], SIGNAL(itemSelectionChanged()), 0114 this, SLOT(slotSelectionChanged())); 0115 } 0116 0117 //////////////////// read/write configuration //////////////////// 0118 0119 void CodeCompletionConfigWidget::readConfig() 0120 { 0121 // read selected and deselected filenames with wordlists 0122 m_wordlist[TexPage] = KileConfig::completeTex(); 0123 m_wordlist[DictionaryPage] = KileConfig::completeDict(); 0124 m_wordlist[AbbreviationPage] = KileConfig::completeAbbrev(); 0125 0126 // set checkbox status 0127 cb_setcursor->setChecked(KileConfig::completeCursor()); 0128 cb_setbullets->setChecked(KileConfig::completeBullets()); 0129 cb_closeenv->setChecked(KileConfig::completeCloseEnv()); 0130 cb_showabbrevview->setChecked(KileConfig::completeShowAbbrev()); 0131 cb_showcwlview->setChecked(KileConfig::showCwlCommands()); 0132 0133 cb_autocomplete->setChecked(KileConfig::completeAuto()); 0134 cb_autocompleteabbrev->setChecked(KileConfig::completeAutoAbbrev()); 0135 0136 sp_latexthreshold->setValue(KileConfig::completeAutoThreshold()); 0137 0138 // insert filenames into listview 0139 for (uint i = TexPage; i < NumPages; ++i) { 0140 setListviewEntries(CompletionPage(i)); 0141 } 0142 } 0143 0144 void CodeCompletionConfigWidget::writeConfig() 0145 { 0146 // get listview entries 0147 for (uint i = TexPage; i < NumPages; ++i) { 0148 m_configChanged |= getListviewEntries(CompletionPage(i)); 0149 } 0150 0151 // Konfigurationslisten abspeichern 0152 KileConfig::setCompleteTex(m_wordlist[TexPage]); 0153 KileConfig::setCompleteDict(m_wordlist[DictionaryPage]); 0154 KileConfig::setCompleteAbbrev(m_wordlist[AbbreviationPage]); 0155 0156 // save checkbox status 0157 KileConfig::setCompleteCursor(cb_setcursor->isChecked()); 0158 KileConfig::setCompleteBullets(cb_setbullets->isChecked()); 0159 KileConfig::setCompleteCloseEnv(cb_closeenv->isChecked()); 0160 KileConfig::setCompleteShowAbbrev(cb_showabbrevview->isChecked()); 0161 KileConfig::setShowCwlCommands(cb_showcwlview->isChecked()); 0162 0163 // read autocompletion settings 0164 bool autoModeLatex = cb_autocomplete->isChecked(); 0165 bool autoModeAbbrev = cb_autocompleteabbrev->isChecked(); 0166 0167 // save settings for Kile autocompletion modes 0168 KileConfig::setCompleteAuto(autoModeLatex); 0169 KileConfig::setCompleteAutoAbbrev(autoModeAbbrev); 0170 KileConfig::setCompleteAutoThreshold(sp_latexthreshold->value()); 0171 0172 // save changed wordlists? 0173 KileConfig::setCompleteChangedLists(m_configChanged); 0174 } 0175 0176 //////////////////// listview //////////////////// 0177 0178 // create ListView for configuration dialog 0179 0180 void CodeCompletionConfigWidget::setListviewEntries(CompletionPage page) 0181 { 0182 QString listname = m_dirname[page]; 0183 QString localdir = m_localCwlDir + listname + '/'; 0184 QString globaldir = m_globalCwlDir + listname + '/'; 0185 0186 // add data from config list into ListView widget 0187 m_listview[page]->setUpdatesEnabled(false); 0188 m_listview[page]->clear(); 0189 for (const auto& curWord : m_wordlist[page]) { 0190 QString basename = curWord.right(curWord.length() - 2); 0191 0192 QTreeWidgetItem *item = new QTreeWidgetItem(m_listview[page], QStringList(basename)); 0193 item->setFlags(item->flags() | Qt::ItemIsUserCheckable); 0194 if (QFileInfo::exists(localdir + basename + ".cwl")) { 0195 item->setCheckState(0, curWord.at(0) == '1' ? Qt::Checked : Qt::Unchecked); 0196 item->setText(1, i18n("yes")); 0197 } 0198 else if (QFileInfo::exists(globaldir + basename + ".cwl")) { 0199 item->setCheckState(0, curWord.at(0) == '1' ? Qt::Checked : Qt::Unchecked); 0200 item->setText(1, i18n("no")); 0201 } 0202 else { 0203 item->setCheckState(0, Qt::Unchecked); 0204 item->setText(1, i18n("File not found")); 0205 } 0206 } 0207 0208 updateColumnWidth(m_listview[page]); 0209 m_listview[page]->setUpdatesEnabled(true); 0210 } 0211 0212 void CodeCompletionConfigWidget::updateColumnWidth(QTreeWidget *listview) 0213 { 0214 listview->resizeColumnToContents(0); 0215 listview->resizeColumnToContents(1); 0216 listview->setColumnWidth(0, listview->columnWidth(0) + 60); 0217 } 0218 0219 bool CodeCompletionConfigWidget::getListviewEntries(CompletionPage page) 0220 { 0221 KILE_DEBUG_MAIN << "===bool CodeCompletionConfigWidget::getListviewEntries(CompletionPage" << page << ")"; 0222 0223 bool changed = false; 0224 0225 // count number of entries 0226 int n = m_listview[page]->topLevelItemCount(); 0227 0228 // there are changes if this number has changed 0229 if(n != m_wordlist[page].count()) { 0230 changed = true; 0231 } 0232 0233 // clear all stringlist with files, if there are no entries 0234 if (n == 0) { 0235 m_wordlist[page].clear(); 0236 return changed; 0237 } 0238 0239 // now check all entries if they have changed 0240 QStringList newfiles; 0241 int index = 0; 0242 QTreeWidgetItemIterator it(m_listview[page]); 0243 while (*it) { 0244 QString s = ((*it)->checkState(0) == Qt::Checked) ? "1-" : "0-"; 0245 s += (*it)->text(0); 0246 newfiles.append(s); 0247 0248 // check for a change 0249 if (index >= m_wordlist[page].count() || m_wordlist[page][index] != s) { 0250 changed = true; 0251 } 0252 0253 // go on 0254 ++it; 0255 index++; 0256 } 0257 0258 // only update if there are changes 0259 if (changed) { 0260 m_wordlist[page] = newfiles; 0261 } 0262 0263 return changed; 0264 } 0265 0266 QTreeWidgetItem* CodeCompletionConfigWidget::getListviewEntry(QTreeWidget *listview, const QString &filename) 0267 { 0268 QList<QTreeWidgetItem*> items = listview->findItems(filename, Qt::MatchExactly); 0269 if (items.empty()) { 0270 return Q_NULLPTR; 0271 } 0272 else { 0273 if (items.count() > 1) { 0274 m_errorHandler->printMessage(KileTool::Info, i18n("Wordlist '%1' contains duplicate entries.", filename), i18n("Completion")); 0275 } 0276 return items.first(); 0277 } 0278 } 0279 0280 //////////////////// tabpages parameter //////////////////// 0281 0282 QTreeWidget *CodeCompletionConfigWidget::getListview(QWidget *page) 0283 { 0284 for (uint i = TexPage; i < NumPages; ++i) { 0285 if (page == m_page[i]) { 0286 return m_listview[i]; 0287 } 0288 } 0289 return 0; 0290 } 0291 0292 QString CodeCompletionConfigWidget::getListname(QWidget *page) 0293 { 0294 for (uint i = TexPage; i < NumPages; ++i) { 0295 if(page == m_page[i]) { 0296 return m_dirname[i]; 0297 } 0298 } 0299 return QString(); 0300 } 0301 0302 //////////////////// shwo tabpages //////////////////// 0303 0304 void CodeCompletionConfigWidget::showPage(QWidget *page) 0305 { 0306 QTreeWidget *listview = getListview(page); 0307 if(listview) { 0308 m_removeFileButton->setEnabled(listview->selectedItems().count() > 0); 0309 } 0310 } 0311 0312 void CodeCompletionConfigWidget::showPage(int index) 0313 { 0314 showPage(m_tabWidget->widget(index)); 0315 } 0316 0317 //////////////////// add/remove new wordlists //////////////////// 0318 0319 void CodeCompletionConfigWidget::addClicked() 0320 { 0321 // determine current subdirectory for current tab page 0322 QString listname = getListname(m_tabWidget->currentWidget()); 0323 QString localPath = m_localCwlDir + listname, globalPath = m_globalCwlDir + listname; 0324 0325 // dialog to add cwl files 0326 ManageCompletionFilesDialog dlg(i18n("Completion Files"), localPath, globalPath, this); 0327 0328 if (dlg.exec()) { 0329 QSet<QString> filenames = dlg.selected(); 0330 if (!filenames.isEmpty()) { 0331 QTreeWidget *listview = getListview(m_tabWidget->currentWidget()); // get current page 0332 for (QSet<QString>::ConstIterator it = filenames.constBegin(); it != filenames.constEnd(); ++it) { 0333 QString filename = *it; 0334 // Reload map of files. 0335 QMap<QString, QString> filemap = KileCodeCompletion::Manager::getAllCwlFiles(localPath, globalPath); 0336 0337 // Could we accept the wordlist? 0338 QFileInfo fi(filemap[filename]); 0339 if (!filename.isEmpty() && fi.exists() && fi.isReadable()) { 0340 QString basename = filename.left(filename.length() - 4); 0341 0342 // Check if this entry already exists. 0343 QTreeWidgetItem* entry = Q_NULLPTR; 0344 if ((entry = getListviewEntry(listview, basename)) == Q_NULLPTR) { 0345 // A new entry has to be created 0346 entry = new QTreeWidgetItem(listview, QStringList(basename)); 0347 } 0348 0349 entry->setFlags(entry->flags() | Qt::ItemIsUserCheckable); 0350 entry->setCheckState(0, Qt::Checked); 0351 entry->setSelected(true); 0352 if (filemap[filename].left(m_localCwlDir.length()) == m_localCwlDir) { 0353 entry->setText(1, i18n("yes")); 0354 } 0355 else { 0356 entry->setText(1, i18n("no")); 0357 } 0358 } 0359 } 0360 updateColumnWidth(listview); 0361 } 0362 } 0363 } 0364 0365 // delete a selected entry 0366 0367 void CodeCompletionConfigWidget::removeClicked() 0368 { 0369 QWidget *page = m_tabWidget->currentWidget(); 0370 QTreeWidget *list = getListview(page); // determine page 0371 0372 foreach(QTreeWidgetItem *item, list->selectedItems()) { 0373 delete item; 0374 } 0375 0376 showPage(page); 0377 } 0378 0379 void CodeCompletionConfigWidget::slotSelectionChanged() 0380 { 0381 QTreeWidget *listview = getListview(m_tabWidget->currentWidget()); // get current page 0382 m_removeFileButton->setEnabled(listview->selectedItems().count() > 0); 0383 } 0384 0385 void CodeCompletionConfigWidget::updateCompletionFilesTab(const QString& path) 0386 { 0387 int localLength = (path.startsWith(m_localCwlDir) ? m_localCwlDir.length() : m_globalCwlDir.length()); 0388 // 'm_globalCwlDir' and 'm_localCwlDir' are guaranteed to end in '/' (see 'KileCodeCompletion::Manager::getCwlBaseDirs()') 0389 QString dirname = path.mid(localLength, path.indexOf('/', localLength) - localLength); 0390 0391 int dirnameIdx = m_dirname.indexOf(dirname); 0392 if (dirnameIdx >= 0) { 0393 m_configChanged |= getListviewEntries(CompletionPage(dirnameIdx)); 0394 setListviewEntries(CompletionPage(dirnameIdx)); 0395 } 0396 } 0397 0398