//============================================================================= // // File : OptionsDialog.cpp // Created on Fri 10 Feb 2006 18:52:18 by Szymon Stefanek // Based on dlg_options.cpp: Tue Jun 11 2000 02:39:12 by Szymon Stefanek // // This file is part of the KVIrc IRC Client distribution // Copyright (C) 2000-2010 Szymon Stefanek // // This program is FREE software. You can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the HOPE that it will be USEFUL, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, write to the Free Software Foundation, // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //============================================================================= #include "OptionsDialog.h" #include "KviApplication.h" #include "KviOptions.h" #include "KviLocale.h" #include "KviIconManager.h" #include "KviMainWindow.h" #include "KviModule.h" #include "KviPointerHashTable.h" #include "KviTalVBox.h" #include "KviTalToolTip.h" #include "KviTalGroupBox.h" #include #include #include #include #include #include #include #include #include #include #include #include #include //FIXME: some headers must be hidden //extern KviModule * g_pOptionsModule; extern KviPointerHashTable * g_pOptionsDialogDict; extern KVIRC_API KviApplication * g_pApp; extern OptionsInstanceManager * g_pOptionsInstanceManager; OptionsDialogFrontWidget::OptionsDialogFrontWidget(QWidget * parent, const QString & szText) : KviOptionsWidget(parent) { setObjectName("general_options_front_widget"); createLayout(); QLabel * l = new QLabel(szText, this); l->setWordWrap(true); l->setAlignment(Qt::AlignTop); layout()->addWidget(l, 0, 0); } OptionsDialogFrontWidget::~OptionsDialogFrontWidget() = default; OptionsDialogTreeWidgetItem::OptionsDialogTreeWidgetItem(QTreeWidget * parent, OptionsWidgetInstanceEntry * e) : QTreeWidgetItem() { m_pInstanceEntry = e; m_pOptionsWidget = nullptr; setText(0, e->szName); setIcon(0, *(g_pIconManager->getSmallIcon(e->eIcon))); parent->insertTopLevelItem(0, this); } OptionsDialogTreeWidgetItem::OptionsDialogTreeWidgetItem(QTreeWidgetItem * parent, OptionsWidgetInstanceEntry * e) : QTreeWidgetItem() { m_pInstanceEntry = e; m_pOptionsWidget = nullptr; setText(0, e->szName); setIcon(0, *(g_pIconManager->getSmallIcon(e->eIcon))); parent->insertChild(0, this); } OptionsDialogTreeWidgetItem::~OptionsDialogTreeWidgetItem() = default; OptionsDialog::OptionsDialog(QWidget * par, const QString & szGroup, bool bModal) : QDialog(par) { setObjectName("general_options_dialog"); setWindowIcon(*(g_pIconManager->getSmallIcon(KviIconManager::KVIrc))); m_szGroup = szGroup; QString szDialogTitle; if(szGroup.isEmpty() || KviQString::equalCI(szGroup, "general")) { szDialogTitle = __tr2qs_ctx("General Preferences", "options"); } else if(KviQString::equalCI(szGroup, "theme")) { szDialogTitle = __tr2qs_ctx("Theme Preferences", "options"); } else { szDialogTitle = __tr2qs_ctx("KVIrc Preferences", "options"); } QString szDialog = __tr2qs_ctx("This dialog contains a set of KVIrc settings.
Use the icons " "on the left to navigate through the option pages. The text box in the " "bottom left corner is a small search engine. It will highlight the " "pages that contain options related to the search term you have entered.", "options"); QString szInfoTips; szInfoTips = __tr2qs_ctx("Many settings have tooltips that can be shown by holding " "the cursor over their label for a few seconds.", "options"); QString szOkCancelButtons = __tr2qs_ctx("When you have finished, click \"OK\" to accept your changes " "or \"Cancel\" to discard them. Clicking \"Apply\" will commit your " "changes without closing the window.", "options"); // clang-format off QString szFrontText = QString( "" \ "" \ "" \ "" \ "" \ "" \ "" \ "
" \ "

%1

" \ "
" \ "

" \ "%2" \ "

" \ "
" \ "

" \ "%3" \ "

" \ "
" \ "

" \ "%4" \ "

" \ "
" ).arg(szDialogTitle, szDialog, szInfoTips, szOkCancelButtons); // clang-format on QString szCaption = szDialogTitle + " - KVIrc"; setWindowTitle(szCaption); QGridLayout * g1 = new QGridLayout(this); QSplitter * spl = new QSplitter(Qt::Horizontal, this); spl->setChildrenCollapsible(false); g1->addWidget(spl, 0, 0, 1, 5); KviTalVBox * vbox = new KviTalVBox(spl); vbox->setSpacing(2); vbox->setMargin(3); // Controlling list view m_pTreeWidget = new QTreeWidget(vbox); m_pTreeWidget->header()->hide(); m_pTreeWidget->setRootIsDecorated(true); m_pTreeWidget->setSortingEnabled(false); m_pTreeWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_pTreeWidget->setCurrentItem(nullptr); connect(m_pTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(treeWidgetItemSelectionChanged(QTreeWidgetItem *, QTreeWidgetItem *))); KviTalHBox * hbox = new KviTalHBox(vbox); hbox->setSpacing(2); hbox->setMargin(3); m_pSearchLineEdit = new QLineEdit(hbox); connect(m_pSearchLineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(searchClicked())); m_pSearchButton = new QToolButton(hbox); m_pSearchButton->setIconSize(QSize(16, 16)); m_pSearchButton->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Search))); connect(m_pSearchButton, SIGNAL(clicked()), this, SLOT(searchClicked())); connect(m_pSearchLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(searchLineEditTextChanged(const QString &))); QString szTip = __tr2qs_ctx("

This is the search tool for this options dialog.

" "

You can enter a search term either in your native " "language or in English and press the button on the right. " "The pages that contain some options related to the " "search term will be highlighted and you will be able " "to quickly find them.

Try \"nickname\" for example.

", "options"); KviTalToolTip::add(m_pSearchLineEdit, szTip); KviTalToolTip::add(m_pSearchButton, szTip); vbox = new KviTalVBox(spl); vbox->setSpacing(2); vbox->setMargin(3); m_pCategoryLabel = new QLabel(" ", vbox); m_pCategoryLabel->setObjectName("labgeneraloptions"); QFrame * f = new QFrame(vbox); f->setFrameStyle(QFrame::HLine | QFrame::Sunken); // Widget stack m_pWidgetStack = new QStackedWidget(vbox); vbox->setStretchFactor(m_pWidgetStack, 1); // First widget visible m_pFrontWidget = new OptionsDialogFrontWidget(m_pWidgetStack, szFrontText); m_pWidgetStack->addWidget(m_pFrontWidget); int idx = m_pWidgetStack->indexOf(m_pFrontWidget); m_pWidgetStack->widget(idx)->raise(); // Ok,Cancel,Help QPushButton * b = new QPushButton(__tr2qs_ctx("&OK", "options"), this); b->setObjectName("btnok"); KviTalToolTip::add(b, __tr2qs_ctx("Close this dialog, accepting all changes.", "options")); connect(b, SIGNAL(clicked()), this, SLOT(okClicked())); //b->setMinimumWidth(whatIsThisWidth); b->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept))); g1->addWidget(b, 1, 2); b = new QPushButton(__tr2qs_ctx("&Apply", "options"), this); b->setObjectName("btnapply"); KviTalToolTip::add(b, __tr2qs_ctx("Commit all changes immediately.", "options")); connect(b, SIGNAL(clicked()), this, SLOT(applyClicked())); b->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept))); g1->addWidget(b, 1, 3); b = new QPushButton(__tr2qs_ctx("Cancel", "options"), this); b->setObjectName("btncancel"); KviTalToolTip::add(b, __tr2qs_ctx("Close this dialog, discarding all changes.", "options")); b->setDefault(true); //b->setMinimumWidth(whatIsThisWidth); connect(b, SIGNAL(clicked()), this, SLOT(cancelClicked())); b->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Discard))); g1->addWidget(b, 1, 4); g1->setRowStretch(0, 1); g1->setColumnStretch(1, 1); fillTreeWidget(nullptr, g_pOptionsInstanceManager->instanceEntryTree(), szGroup); if(!parent()) { if(KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry).y() < 5) KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry) .setY(5); //setGeometry(KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry)); resize(KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry).width(), KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry).height()); move(KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry).x(), KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry).y()); } new QShortcut(Qt::Key_Escape, this, SLOT(close())); if(bModal) setWindowModality(par ? Qt::WindowModal : Qt::ApplicationModal); } OptionsDialog::~OptionsDialog() { if(!parent()) KVI_OPTION_RECT(KviOption_rectGeneralOptionsDialogGeometry) = QRect(pos().x(), pos().y(), size().width(), size().height()); if(g_pOptionsDialogDict) g_pOptionsDialogDict->remove(m_szGroup); } void OptionsDialog::showEvent(QShowEvent * e) { // setup a minimum size and move to the screen the main kvirc window is QRect r = g_pApp->desktop()->screenGeometry(g_pMainWindow); int w = r.width(); int h = r.height(); int ww = width(); int wh = height(); if(w < 800) { // 640x480 if(ww < 630) ww = 630; } else { if(ww < 770) ww = 770; } setGeometry(r.x() + ((w - ww) / 2), r.y() + ((h - wh) / 2), ww, wh); QWidget::showEvent(e); } void OptionsDialog::searchLineEditTextChanged(const QString &) { QString txt = m_pSearchLineEdit->text().trimmed(); m_pSearchButton->setEnabled(txt.length() > 0); } bool OptionsDialog::searchInSelectors(KviOptionsWidget * pOptionsWidget, const QStringList & lKeywords) { KviPointerList * selectors = pOptionsWidget->selectors(); bool bFoundSomethingHere = false; if(selectors->count() > 0) { for(unsigned int i = 0; i < selectors->count(); i++) { QString szText = selectors->at(i)->textForSearch(); QWidget * pWidget = selectors->at(i)->widgetToHighlight(); if(!pWidget) continue; QString szTmp = pWidget->toolTip(); szTmp = szTmp.replace(QRegExp("<[^<>]+>"), ""); szText.append(szTmp); if(!szText.isEmpty()) { bool bOk = true; for(int j = 0; j < lKeywords.count(); j++) { if(szText.indexOf(lKeywords.at(j), 0, Qt::CaseInsensitive) == -1) { bOk = false; break; } } if(bOk) { bFoundSomethingHere = true; } QFont font = pWidget->font(); font.setBold(bOk); font.setUnderline(bOk); pWidget->setFont(font); } } } return bFoundSomethingHere; } bool OptionsDialog::recursiveSearch(OptionsDialogTreeWidgetItem * pItem, const QStringList & lKeywords) { if(!pItem) return false; if(!pItem->m_pOptionsWidget) { pItem->m_pOptionsWidget = g_pOptionsInstanceManager->getInstance(pItem->m_pInstanceEntry, m_pWidgetStack); m_pWidgetStack->addWidget(pItem->m_pOptionsWidget); } bool bFoundSomethingHere = false; KviOptionsWidget * pOptionsWidget = pItem->m_pOptionsWidget; QTabWidget * pTab = pOptionsWidget->tabWidget(); if(pTab) { for(int i = 0; i < pTab->count(); i++) { QString szTxt = pTab->tabText(i); if(KviQString::equalCIN(szTxt, ">>> ", 4)) { szTxt.replace(">>> ", ""); szTxt.replace(" <<<", ""); } if(searchInSelectors((KviOptionsWidget *)pTab->widget(i), lKeywords)) { bFoundSomethingHere = true; szTxt.insert(0, ">>> "); szTxt += QString(" <<<"); } pTab->setTabText(i, szTxt); } } else { if(searchInSelectors(pOptionsWidget, lKeywords)) bFoundSomethingHere = true; } QStringList szInstanceKeywords = pItem->m_pInstanceEntry->szKeywords.split(QChar(',')); // debug all the "search keywords" for each entry in the options tree // qDebug("OPT %s",pItem->m_pInstanceEntry->szKeywords.toUtf8().data()); for(int i = 0; i < szInstanceKeywords.count() && !bFoundSomethingHere; i++) for(int j = 0; j < lKeywords.count() && !bFoundSomethingHere; j++) if(szInstanceKeywords.at(i).contains(lKeywords.at(j), Qt::CaseInsensitive)) bFoundSomethingHere = true; if(bFoundSomethingHere) { pItem->setForeground(0, Qt::yellow); pItem->setBackground(0, Qt::red); } else { pItem->setForeground(0, Qt::black); pItem->setBackground(0, Qt::transparent); } bool bFoundSomethingInside = false; int ccount = pItem->childCount(); if(ccount > 0) { for(int j = 0; j < ccount; j++) { OptionsDialogTreeWidgetItem * pChild = (OptionsDialogTreeWidgetItem *)pItem->child(j); bool bRet = recursiveSearch(pChild, lKeywords); if(bRet) bFoundSomethingInside = true; } } pItem->setSelected(false); pItem->setExpanded(bFoundSomethingInside); return (bFoundSomethingInside || bFoundSomethingHere); } void OptionsDialog::search(const QStringList & lKeywords) { m_pTreeWidget->setUpdatesEnabled(false); int count = m_pTreeWidget->topLevelItemCount(); for(int i = 0; i < count; i++) { OptionsDialogTreeWidgetItem * pChild = (OptionsDialogTreeWidgetItem *)m_pTreeWidget->topLevelItem(i); recursiveSearch(pChild, lKeywords); } m_pTreeWidget->setUpdatesEnabled(true); m_pTreeWidget->update(); } void OptionsDialog::search(const QString & szKeywords) { QStringList lKeywords = szKeywords.split(" ", QString::SkipEmptyParts); search(lKeywords); } void OptionsDialog::clearSearch() { m_pTreeWidget->setUpdatesEnabled(false); QTreeWidgetItemIterator it(m_pTreeWidget); while (*it) { (*it)->setForeground(0, Qt::black); (*it)->setBackground(0, Qt::transparent); ++it; } m_pTreeWidget->setUpdatesEnabled(true); m_pTreeWidget->update(); } void OptionsDialog::searchClicked() { QString szTxt = m_pSearchLineEdit->text().trimmed(); if(szTxt.length() > 1) search(szTxt); else clearSearch(); } void OptionsDialog::fillTreeWidget(QTreeWidgetItem * p, KviPointerList * l, const QString & szGroup, bool bNotContainedOnly) { if(!l) return; OptionsDialogTreeWidgetItem * it; OptionsWidgetInstanceEntry * e; KviPointerList tmp; tmp.setAutoDelete(false); for(e = l->first(); e; e = l->next()) { // must be in the correct group // if we want only containers then well.. must be one e->bDoInsert = KviQString::equalCI(szGroup, e->szGroup) && ((!bNotContainedOnly) || e->bIsContainer || e->bIsNotContained); OptionsWidgetInstanceEntry * ee = tmp.first(); int idx = 0; while(ee) { if(ee->iPriority >= e->iPriority) break; idx++; ee = tmp.next(); } tmp.insert(idx, e); } for(e = tmp.first(); e; e = tmp.next()) { if(e->bDoInsert) { if(p) it = new OptionsDialogTreeWidgetItem(p, e); else it = new OptionsDialogTreeWidgetItem(m_pTreeWidget, e); if(!it->m_pOptionsWidget) { it->m_pOptionsWidget = g_pOptionsInstanceManager->getInstance(it->m_pInstanceEntry, m_pWidgetStack); if(it->m_pOptionsWidget) m_pWidgetStack->addWidget(it->m_pOptionsWidget); } } else { it = (OptionsDialogTreeWidgetItem *)p; } if(e->pChildList) { if(e->bIsContainer) { // it's a container: add only eventual not contained children (containers or explicitly marked as not contained) fillTreeWidget(it, e->pChildList, szGroup, true); } else { // it's not a container, add any children fillTreeWidget(it, e->pChildList, szGroup, false); } } } } void OptionsDialog::treeWidgetItemSelectionChanged(QTreeWidgetItem * it, QTreeWidgetItem *) { if(it) { QString str = it->text(0); QTreeWidgetItem * par = it->parent(); while(par) { str.prepend(" :: "); str.prepend(par->text(0)); par = par->parent(); } str.prepend(""); str += ""; OptionsDialogTreeWidgetItem * i = (OptionsDialogTreeWidgetItem *)it; if(!i->m_pOptionsWidget) { i->m_pOptionsWidget = g_pOptionsInstanceManager->getInstance(i->m_pInstanceEntry, m_pWidgetStack); m_pWidgetStack->addWidget(i->m_pOptionsWidget); } //int idx = m_pWidgetStack->indexOf(i->m_pOptionsWidget); m_pWidgetStack->setCurrentWidget(i->m_pOptionsWidget); m_pCategoryLabel->setText(str); } } void OptionsDialog::pageWantsToSwitchToAdvancedPage(KviOptionsWidget *) { // unused } void OptionsDialog::applyClicked() { apply(false); } void OptionsDialog::apply(bool bDialogAboutToClose) { int count = m_pTreeWidget->topLevelItemCount(); int curTab = -1; OptionsDialogTreeWidgetItem * it; if(!bDialogAboutToClose) { // bring up the current widget again! it = (OptionsDialogTreeWidgetItem *)m_pTreeWidget->currentItem(); //checking if the check of the check is checkable if(it) if(it->m_pOptionsWidget) if(it->m_pOptionsWidget->tabWidget()) curTab = it->m_pOptionsWidget->tabWidget()->currentIndex(); } for(int i = 0; i < count; i++) { it = (OptionsDialogTreeWidgetItem *)m_pTreeWidget->topLevelItem(i); recursiveCommit(it); } if(!bDialogAboutToClose) { // bring up the current widget again! it = (OptionsDialogTreeWidgetItem *)m_pTreeWidget->currentItem(); if(it) { treeWidgetItemSelectionChanged(it, nullptr); if(curTab > 0 && it->m_pOptionsWidget) if(it->m_pOptionsWidget->tabWidget()) it->m_pOptionsWidget->tabWidget()->setCurrentIndex(curTab); } } g_pApp->saveConfiguration(); } void OptionsDialog::okClicked() { apply(true); deleteLater(); } void OptionsDialog::cancelClicked() { deleteLater(); } void OptionsDialog::closeEvent(QCloseEvent * e) { e->ignore(); deleteLater(); } void OptionsDialog::recursiveCommit(OptionsDialogTreeWidgetItem * it) { // First commit the children if(!it) return; int count = it->childCount(); for(int i = 0; i < count; i++) { OptionsDialogTreeWidgetItem * pChild = (OptionsDialogTreeWidgetItem *)it->child(i); recursiveCommit(pChild); } // then the parents if(it->m_pOptionsWidget) { it->m_pOptionsWidget->commit(); delete it->m_pOptionsWidget; it->m_pOptionsWidget = nullptr; } //refreshTreeWidget(); // <-- this tends to jump into infinite recursion } void OptionsDialog::keyPressEvent(QKeyEvent * e) { if(e->key() == Qt::Key_Return) e->accept(); else e->ignore(); }