File indexing completed on 2024-04-28 16:31:53
0001 /*************************************************************************** 0002 Copyright (C) 2001-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include <config.h> 0026 0027 #include "configdialog.h" 0028 #include "field.h" 0029 #include "collection.h" 0030 #include "collectionfactory.h" 0031 #include "fetch/execexternalfetcher.h" 0032 #include "fetch/fetchmanager.h" 0033 #include "fetch/configwidget.h" 0034 #include "controller.h" 0035 #include "fetcherconfigdialog.h" 0036 #include "tellico_kernel.h" 0037 #include "utils/tellico_utils.h" 0038 #include "utils/string_utils.h" 0039 #include "config/tellico_config.h" 0040 #include "images/imagefactory.h" 0041 #include "gui/combobox.h" 0042 #include "gui/collectiontypecombo.h" 0043 #include "gui/previewdialog.h" 0044 #include "newstuff/manager.h" 0045 #include "fieldformat.h" 0046 #include "tellico_debug.h" 0047 0048 #include <KLocalizedString> 0049 #include <KConfig> 0050 #include <KAcceleratorManager> 0051 #include <KColorCombo> 0052 #include <KHelpClient> 0053 #include <KRecentDirs> 0054 0055 #ifdef ENABLE_KNEWSTUFF3 0056 #include <KNS3/DownloadDialog> 0057 #endif 0058 0059 #include <QSpinBox> 0060 #include <QLineEdit> 0061 #include <QPushButton> 0062 #include <QSize> 0063 #include <QLayout> 0064 #include <QLabel> 0065 #include <QCheckBox> 0066 #include <QPixmap> 0067 #include <QRegularExpression> 0068 #include <QFileInfo> 0069 #include <QRadioButton> 0070 #include <QFrame> 0071 #include <QFontComboBox> 0072 #include <QGroupBox> 0073 #include <QButtonGroup> 0074 #include <QInputDialog> 0075 #include <QVBoxLayout> 0076 #include <QHBoxLayout> 0077 #include <QApplication> 0078 #include <QTimer> 0079 #include <QFileDialog> 0080 0081 namespace { 0082 static const int CONFIG_MIN_WIDTH = 640; 0083 static const int CONFIG_MIN_HEIGHT = 420; 0084 } 0085 0086 using Tellico::ConfigDialog; 0087 0088 ConfigDialog::ConfigDialog(QWidget* parent_) 0089 : KPageDialog(parent_) 0090 , m_initializedPages(0) 0091 , m_modifying(false) 0092 , m_okClicked(false) { 0093 setFaceType(List); 0094 setModal(true); 0095 setWindowTitle(i18n("Configure Tellico")); 0096 setStandardButtons(QDialogButtonBox::Help | 0097 QDialogButtonBox::Ok | 0098 QDialogButtonBox::Apply | 0099 QDialogButtonBox::Cancel | 0100 QDialogButtonBox::RestoreDefaults); 0101 0102 setupGeneralPage(); 0103 setupPrintingPage(); 0104 setupTemplatePage(); 0105 setupFetchPage(); 0106 0107 updateGeometry(); 0108 QSize s = sizeHint(); 0109 resize(qMax(s.width(), CONFIG_MIN_WIDTH), qMax(s.height(), CONFIG_MIN_HEIGHT)); 0110 0111 // OK button is connected to buttonBox accepted() signal which is already connected to accept() slot 0112 connect(button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &ConfigDialog::slotApply); 0113 connect(button(QDialogButtonBox::Help), &QAbstractButton::clicked, this, &ConfigDialog::slotHelp); 0114 connect(button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, &ConfigDialog::slotDefault); 0115 0116 button(QDialogButtonBox::Ok)->setEnabled(false); 0117 button(QDialogButtonBox::Apply)->setEnabled(false); 0118 button(QDialogButtonBox::Ok)->setDefault(true); 0119 button(QDialogButtonBox::Ok)->setShortcut(Qt::CTRL | Qt::Key_Return); 0120 0121 connect(this, &KPageDialog::currentPageChanged, this, &ConfigDialog::slotInitPage); 0122 } 0123 0124 ConfigDialog::~ConfigDialog() { 0125 foreach(Fetch::ConfigWidget* widget, m_newStuffConfigWidgets) { 0126 widget->removed(); 0127 } 0128 } 0129 0130 void ConfigDialog::slotInitPage(KPageWidgetItem* item_) { 0131 Q_ASSERT(item_); 0132 // every page item has a frame 0133 // if the frame has no layout, then we need to initialize the itme 0134 QFrame* frame = ::qobject_cast<QFrame*>(item_->widget()); 0135 Q_ASSERT(frame); 0136 if(frame->layout()) { 0137 return; 0138 } 0139 0140 const QString name = item_->name(); 0141 // these names must be kept in sync with the page names 0142 if(name == i18n("General")) { 0143 initGeneralPage(frame); 0144 } else if(name == i18n("Printing")) { 0145 initPrintingPage(frame); 0146 } else if(name == i18n("Templates")) { 0147 initTemplatePage(frame); 0148 } else if(name == i18n("Data Sources")) { 0149 initFetchPage(frame); 0150 } 0151 } 0152 0153 void ConfigDialog::accept() { 0154 m_okClicked = true; 0155 slotApply(); 0156 KPageDialog::accept(); 0157 m_okClicked = false; 0158 } 0159 0160 void ConfigDialog::slotApply() { 0161 emit signalConfigChanged(); 0162 button(QDialogButtonBox::Apply)->setEnabled(false); 0163 } 0164 0165 void ConfigDialog::slotDefault() { 0166 // only change the defaults on the active page 0167 Config::self()->useDefaults(true); 0168 const QString name = currentPage()->name(); 0169 if(name == i18n("General")) { 0170 readGeneralConfig(); 0171 } else if(name == i18n("Printing")) { 0172 readPrintingConfig(); 0173 } else if(name == i18n("Templates")) { 0174 readTemplateConfig(); 0175 } 0176 Config::self()->useDefaults(false); 0177 slotModified(); 0178 } 0179 0180 void ConfigDialog::slotHelp() { 0181 const QString name = currentPage()->name(); 0182 // these names must be kept in sync with the page names 0183 if(name == i18n("General")) { 0184 KHelpClient::invokeHelp(QStringLiteral("general-options")); 0185 } else if(name == i18n("Printing")) { 0186 KHelpClient::invokeHelp(QStringLiteral("printing-options")); 0187 } else if(name == i18n("Templates")) { 0188 KHelpClient::invokeHelp(QStringLiteral("template-options")); 0189 } else if(name == i18n("Data Sources")) { 0190 KHelpClient::invokeHelp(QStringLiteral("internet-sources-options")); 0191 } 0192 } 0193 0194 bool ConfigDialog::isPageInitialized(Page page_) const { 0195 return m_initializedPages & page_; 0196 } 0197 0198 void ConfigDialog::setupGeneralPage() { 0199 QFrame* frame = new QFrame(this); 0200 KPageWidgetItem* page = new KPageWidgetItem(frame, i18n("General")); 0201 page->setHeader(i18n("General Options")); 0202 page->setIcon(QIcon::fromTheme(QStringLiteral("tellico"), QIcon(QLatin1String(":/icons/tellico")))); 0203 addPage(page); 0204 0205 // since this is the first page, go ahead and lay it out 0206 initGeneralPage(frame); 0207 } 0208 0209 void ConfigDialog::initGeneralPage(QFrame* frame) { 0210 QVBoxLayout* l = new QVBoxLayout(frame); 0211 0212 m_cbOpenLastFile = new QCheckBox(i18n("&Reopen file at startup"), frame); 0213 m_cbOpenLastFile->setWhatsThis(i18n("If checked, the file that was last open " 0214 "will be re-opened at program start-up.")); 0215 l->addWidget(m_cbOpenLastFile); 0216 connect(m_cbOpenLastFile, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0217 0218 m_cbShowTipDay = new QCheckBox(i18n("&Show \"Tip of the Day\" at startup"), frame); 0219 m_cbShowTipDay->setWhatsThis(i18n("If checked, the \"Tip of the Day\" will be " 0220 "shown at program start-up.")); 0221 l->addWidget(m_cbShowTipDay); 0222 connect(m_cbShowTipDay, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0223 0224 m_cbEnableWebcam = new QCheckBox(i18n("&Enable webcam for barcode scanning"), frame); 0225 m_cbEnableWebcam->setWhatsThis(i18n("If checked, the input from a webcam will be used " 0226 "to scan barcodes for searching.")); 0227 l->addWidget(m_cbEnableWebcam); 0228 connect(m_cbEnableWebcam, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0229 0230 QGroupBox* imageGroupBox = new QGroupBox(i18n("Image Storage Options"), frame); 0231 l->addWidget(imageGroupBox); 0232 m_rbImageInFile = new QRadioButton(i18n("Store images in data file"), imageGroupBox); 0233 m_rbImageInAppDir = new QRadioButton(i18n("Store images in common application directory"), imageGroupBox); 0234 m_rbImageInLocalDir = new QRadioButton(i18n("Store images in directory relative to data file"), imageGroupBox); 0235 imageGroupBox->setWhatsThis(i18n("Images may be saved in the data file itself, which can " 0236 "cause Tellico to run slowly, stored in the Tellico " 0237 "application directory, or stored in a directory in the " 0238 "same location as the data file.")); 0239 QVBoxLayout* imageGroupLayout = new QVBoxLayout(imageGroupBox); 0240 imageGroupLayout->addWidget(m_rbImageInFile); 0241 imageGroupLayout->addWidget(m_rbImageInAppDir); 0242 imageGroupLayout->addWidget(m_rbImageInLocalDir); 0243 imageGroupBox->setLayout(imageGroupLayout); 0244 0245 QButtonGroup* imageGroup = new QButtonGroup(frame); 0246 imageGroup->addButton(m_rbImageInFile); 0247 imageGroup->addButton(m_rbImageInAppDir); 0248 imageGroup->addButton(m_rbImageInLocalDir); 0249 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) 0250 void (QButtonGroup::* buttonClicked)(int) = &QButtonGroup::buttonClicked; 0251 connect(imageGroup, buttonClicked, this, &ConfigDialog::slotModified); 0252 #else 0253 connect(imageGroup, &QButtonGroup::idClicked, this, &ConfigDialog::slotModified); 0254 #endif 0255 0256 QGroupBox* formatGroup = new QGroupBox(i18n("Formatting Options"), frame); 0257 l->addWidget(formatGroup); 0258 QVBoxLayout* formatGroupLayout = new QVBoxLayout(formatGroup); 0259 formatGroup->setLayout(formatGroupLayout); 0260 0261 m_cbCapitalize = new QCheckBox(i18n("Auto capitalize &titles and names"), formatGroup); 0262 m_cbCapitalize->setWhatsThis(i18n("If checked, titles and names will " 0263 "be automatically capitalized.")); 0264 connect(m_cbCapitalize, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0265 formatGroupLayout->addWidget(m_cbCapitalize); 0266 0267 m_cbFormat = new QCheckBox(i18n("Auto &format titles and names"), formatGroup); 0268 m_cbFormat->setWhatsThis(i18n("If checked, titles and names will " 0269 "be automatically formatted.")); 0270 connect(m_cbFormat, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0271 formatGroupLayout->addWidget(m_cbFormat); 0272 0273 QWidget* g1 = new QWidget(formatGroup); 0274 QGridLayout* g1Layout = new QGridLayout(g1); 0275 g1->setLayout(g1Layout); 0276 formatGroupLayout->addWidget(g1); 0277 0278 QLabel* lab = new QLabel(i18n("No capitali&zation:"), g1); 0279 g1Layout->addWidget(lab, 0, 0); 0280 m_leCapitals = new QLineEdit(g1); 0281 g1Layout->addWidget(m_leCapitals, 0, 1); 0282 lab->setBuddy(m_leCapitals); 0283 QString whats = i18n("<qt>A list of words which should not be capitalized. Multiple values " 0284 "should be separated by a semi-colon.</qt>"); 0285 lab->setWhatsThis(whats); 0286 m_leCapitals->setWhatsThis(whats); 0287 connect(m_leCapitals, &QLineEdit::textChanged, this, &ConfigDialog::slotModified); 0288 0289 lab = new QLabel(i18n("Artic&les:"), g1); 0290 g1Layout->addWidget(lab, 1, 0); 0291 m_leArticles = new QLineEdit(g1); 0292 g1Layout->addWidget(m_leArticles, 1, 1); 0293 lab->setBuddy(m_leArticles); 0294 whats = i18n("<qt>A list of words which should be considered as articles " 0295 "if they are the first word in a title. Multiple values " 0296 "should be separated by a semi-colon.</qt>"); 0297 lab->setWhatsThis(whats); 0298 m_leArticles->setWhatsThis(whats); 0299 connect(m_leArticles, &QLineEdit::textChanged, this, &ConfigDialog::slotModified); 0300 0301 lab = new QLabel(i18n("Personal suffi&xes:"), g1); 0302 g1Layout->addWidget(lab, 2, 0); 0303 m_leSuffixes = new QLineEdit(g1); 0304 g1Layout->addWidget(m_leSuffixes, 2, 1); 0305 lab->setBuddy(m_leSuffixes); 0306 whats = i18n("<qt>A list of suffixes which might be used in personal names. Multiple values " 0307 "should be separated by a semi-colon.</qt>"); 0308 lab->setWhatsThis(whats); 0309 m_leSuffixes->setWhatsThis(whats); 0310 connect(m_leSuffixes, &QLineEdit::textChanged, this, &ConfigDialog::slotModified); 0311 0312 lab = new QLabel(i18n("Surname &prefixes:"), g1); 0313 g1Layout->addWidget(lab, 3, 0); 0314 m_lePrefixes = new QLineEdit(g1); 0315 g1Layout->addWidget(m_lePrefixes, 3, 1); 0316 lab->setBuddy(m_lePrefixes); 0317 whats = i18n("<qt>A list of prefixes which might be used in surnames. Multiple values " 0318 "should be separated by a semi-colon.</qt>"); 0319 lab->setWhatsThis(whats); 0320 m_lePrefixes->setWhatsThis(whats); 0321 connect(m_lePrefixes, &QLineEdit::textChanged, this, &ConfigDialog::slotModified); 0322 0323 // stretch to fill lower area 0324 l->addStretch(1); 0325 m_initializedPages |= General; 0326 readGeneralConfig(); 0327 } 0328 0329 void ConfigDialog::setupPrintingPage() { 0330 QFrame* frame = new QFrame(this); 0331 KPageWidgetItem* page = new KPageWidgetItem(frame, i18n("Printing")); 0332 page->setHeader(i18n("Printing Options")); 0333 page->setIcon(QIcon::fromTheme(QStringLiteral("printer"))); 0334 addPage(page); 0335 } 0336 0337 void ConfigDialog::initPrintingPage(QFrame* frame) { 0338 QVBoxLayout* l = new QVBoxLayout(frame); 0339 0340 QGroupBox* formatOptions = new QGroupBox(i18n("Formatting Options"), frame); 0341 l->addWidget(formatOptions); 0342 QVBoxLayout* formatLayout = new QVBoxLayout(formatOptions); 0343 formatOptions->setLayout(formatLayout); 0344 0345 m_cbPrintFormatted = new QCheckBox(i18n("&Format titles and names"), formatOptions); 0346 m_cbPrintFormatted->setWhatsThis(i18n("If checked, titles and names will be automatically formatted.")); 0347 connect(m_cbPrintFormatted, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0348 formatLayout->addWidget(m_cbPrintFormatted); 0349 0350 m_cbPrintHeaders = new QCheckBox(i18n("&Print field headers"), formatOptions); 0351 m_cbPrintHeaders->setWhatsThis(i18n("If checked, the field names will be printed as table headers.")); 0352 connect(m_cbPrintHeaders, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0353 formatLayout->addWidget(m_cbPrintHeaders); 0354 0355 QGroupBox* groupOptions = new QGroupBox(i18n("Grouping Options"), frame); 0356 l->addWidget(groupOptions); 0357 QVBoxLayout* groupLayout = new QVBoxLayout(groupOptions); 0358 groupOptions->setLayout(groupLayout); 0359 0360 m_cbPrintGrouped = new QCheckBox(i18n("&Group the entries"), groupOptions); 0361 m_cbPrintGrouped->setWhatsThis(i18n("If checked, the entries will be grouped by the selected field.")); 0362 connect(m_cbPrintGrouped, &QAbstractButton::clicked, this, &ConfigDialog::slotModified); 0363 groupLayout->addWidget(m_cbPrintGrouped); 0364 0365 QGroupBox* imageOptions = new QGroupBox(i18n("Image Options"), frame); 0366 l->addWidget(imageOptions); 0367 0368 QGridLayout* gridLayout = new QGridLayout(imageOptions); 0369 imageOptions->setLayout(gridLayout); 0370 0371 QLabel* lab = new QLabel(i18n("Maximum image &width:"), imageOptions); 0372 gridLayout->addWidget(lab, 0, 0); 0373 m_imageWidthBox = new QSpinBox(imageOptions); 0374 m_imageWidthBox->setMaximum(999); 0375 m_imageWidthBox->setMinimum(0); 0376 m_imageWidthBox->setValue(50); 0377 gridLayout->addWidget(m_imageWidthBox, 0, 1); 0378 m_imageWidthBox->setSuffix(QStringLiteral(" px")); 0379 lab->setBuddy(m_imageWidthBox); 0380 QString whats = i18n("The maximum width of the images in the printout. The aspect ratio is preserved."); 0381 lab->setWhatsThis(whats); 0382 m_imageWidthBox->setWhatsThis(whats); 0383 void (QSpinBox::* valueChanged)(int) = &QSpinBox::valueChanged; 0384 connect(m_imageWidthBox, valueChanged, this, &ConfigDialog::slotModified); 0385 0386 lab = new QLabel(i18n("&Maximum image height:"), imageOptions); 0387 gridLayout->addWidget(lab, 1, 0); 0388 m_imageHeightBox = new QSpinBox(imageOptions); 0389 m_imageHeightBox->setMaximum(999); 0390 m_imageHeightBox->setMinimum(0); 0391 m_imageHeightBox->setValue(50); 0392 gridLayout->addWidget(m_imageHeightBox, 1, 1); 0393 m_imageHeightBox->setSuffix(QStringLiteral(" px")); 0394 lab->setBuddy(m_imageHeightBox); 0395 whats = i18n("The maximum height of the images in the printout. The aspect ratio is preserved."); 0396 lab->setWhatsThis(whats); 0397 m_imageHeightBox->setWhatsThis(whats); 0398 connect(m_imageHeightBox, valueChanged, this, &ConfigDialog::slotModified); 0399 0400 // stretch to fill lower area 0401 l->addStretch(1); 0402 m_initializedPages |= Printing; 0403 readPrintingConfig(); 0404 } 0405 0406 void ConfigDialog::setupTemplatePage() { 0407 QFrame* frame = new QFrame(this); 0408 KPageWidgetItem* page = new KPageWidgetItem(frame, i18n("Templates")); 0409 page->setHeader(i18n("Template Options")); 0410 // odd icon, I know, matches KMail, though... 0411 page->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-theme"))); 0412 addPage(page); 0413 } 0414 0415 void ConfigDialog::initTemplatePage(QFrame* frame) { 0416 QVBoxLayout* l = new QVBoxLayout(frame); 0417 0418 QGridLayout* gridLayout = new QGridLayout(); 0419 l->addLayout(gridLayout); 0420 0421 int row = -1; 0422 // so I can reuse an i18n string, a plain label can't have an '&' 0423 QString s = KLocalizedString::removeAcceleratorMarker(i18n("Collection &type:")); 0424 QLabel* lab = new QLabel(s, frame); 0425 gridLayout->addWidget(lab, ++row, 0); 0426 const int collType = Kernel::self()->collectionType(); 0427 lab = new QLabel(CollectionFactory::nameHash().value(collType), frame); 0428 gridLayout->addWidget(lab, row, 1, 1, 2); 0429 0430 lab = new QLabel(i18n("Template:"), frame); 0431 m_templateCombo = new GUI::ComboBox(frame); 0432 void (QComboBox::* activatedInt)(int) = &QComboBox::activated; 0433 connect(m_templateCombo, activatedInt, this, &ConfigDialog::slotModified); 0434 lab->setBuddy(m_templateCombo); 0435 QString whats = i18n("Select the template to use for the current type of collections. " 0436 "Not all templates will use the font and color settings."); 0437 lab->setWhatsThis(whats); 0438 m_templateCombo->setWhatsThis(whats); 0439 gridLayout->addWidget(lab, ++row, 0); 0440 gridLayout->addWidget(m_templateCombo, row, 1); 0441 0442 QPushButton* btn = new QPushButton(i18n("&Preview..."), frame); 0443 btn->setWhatsThis(i18n("Show a preview of the template")); 0444 btn->setIcon(QIcon::fromTheme(QStringLiteral("zoom-original"))); 0445 gridLayout->addWidget(btn, row, 2); 0446 connect(btn, &QAbstractButton::clicked, this, &ConfigDialog::slotShowTemplatePreview); 0447 0448 // so the button is squeezed small 0449 gridLayout->setColumnStretch(0, 10); 0450 gridLayout->setColumnStretch(1, 10); 0451 0452 loadTemplateList(); 0453 0454 // QLabel* l1 = new QLabel(i18n("The options below will be passed to the template, but not " 0455 // "all templates will use them. Some fonts and colors may be " 0456 // "specified directly in the template."), frame); 0457 // l1->setTextFormat(Qt::RichText); 0458 // l->addWidget(l1); 0459 0460 QGroupBox* fontGroup = new QGroupBox(i18n("Font Options"), frame); 0461 l->addWidget(fontGroup); 0462 0463 row = -1; 0464 QGridLayout* fontLayout = new QGridLayout(); 0465 fontGroup->setLayout(fontLayout); 0466 0467 lab = new QLabel(i18n("Font:"), fontGroup); 0468 fontLayout->addWidget(lab, ++row, 0); 0469 m_fontCombo = new QFontComboBox(fontGroup); 0470 fontLayout->addWidget(m_fontCombo, row, 1); 0471 connect(m_fontCombo, activatedInt, this, &ConfigDialog::slotModified); 0472 lab->setBuddy(m_fontCombo); 0473 whats = i18n("This font is passed to the template used in the Entry View."); 0474 lab->setWhatsThis(whats); 0475 m_fontCombo->setWhatsThis(whats); 0476 0477 fontLayout->addWidget(new QLabel(i18n("Size:"), fontGroup), ++row, 0); 0478 m_fontSizeInput = new QSpinBox(fontGroup); 0479 m_fontSizeInput->setMaximum(30); // 30 is same max as konq config 0480 m_fontSizeInput->setMinimum(5); 0481 m_fontSizeInput->setSuffix(QStringLiteral("pt")); 0482 fontLayout->addWidget(m_fontSizeInput, row, 1); 0483 void (QSpinBox::* valueChangedInt)(int) = &QSpinBox::valueChanged; 0484 connect(m_fontSizeInput, valueChangedInt, this, &ConfigDialog::slotModified); 0485 lab->setBuddy(m_fontSizeInput); 0486 lab->setWhatsThis(whats); 0487 m_fontSizeInput->setWhatsThis(whats); 0488 0489 QGroupBox* colGroup = new QGroupBox(i18n("Color Options"), frame); 0490 l->addWidget(colGroup); 0491 0492 row = -1; 0493 QGridLayout* colLayout = new QGridLayout(); 0494 colGroup->setLayout(colLayout); 0495 0496 lab = new QLabel(i18n("Background color:"), colGroup); 0497 colLayout->addWidget(lab, ++row, 0); 0498 m_baseColorCombo = new KColorCombo(colGroup); 0499 colLayout->addWidget(m_baseColorCombo, row, 1); 0500 connect(m_baseColorCombo, activatedInt, this, &ConfigDialog::slotModified); 0501 lab->setBuddy(m_baseColorCombo); 0502 whats = i18n("This color is passed to the template used in the Entry View."); 0503 lab->setWhatsThis(whats); 0504 m_baseColorCombo->setWhatsThis(whats); 0505 0506 lab = new QLabel(i18n("Text color:"), colGroup); 0507 colLayout->addWidget(lab, ++row, 0); 0508 m_textColorCombo = new KColorCombo(colGroup); 0509 colLayout->addWidget(m_textColorCombo, row, 1); 0510 connect(m_textColorCombo, activatedInt, this, &ConfigDialog::slotModified); 0511 lab->setBuddy(m_textColorCombo); 0512 lab->setWhatsThis(whats); 0513 m_textColorCombo->setWhatsThis(whats); 0514 0515 lab = new QLabel(i18n("Highlight color:"), colGroup); 0516 colLayout->addWidget(lab, ++row, 0); 0517 m_highBaseColorCombo = new KColorCombo(colGroup); 0518 colLayout->addWidget(m_highBaseColorCombo, row, 1); 0519 connect(m_highBaseColorCombo, activatedInt, this, &ConfigDialog::slotModified); 0520 lab->setBuddy(m_highBaseColorCombo); 0521 lab->setWhatsThis(whats); 0522 m_highBaseColorCombo->setWhatsThis(whats); 0523 0524 lab = new QLabel(i18n("Highlighted text color:"), colGroup); 0525 colLayout->addWidget(lab, ++row, 0); 0526 m_highTextColorCombo = new KColorCombo(colGroup); 0527 colLayout->addWidget(m_highTextColorCombo, row, 1); 0528 connect(m_highTextColorCombo, activatedInt, this, &ConfigDialog::slotModified); 0529 lab->setBuddy(m_highTextColorCombo); 0530 lab->setWhatsThis(whats); 0531 m_highTextColorCombo->setWhatsThis(whats); 0532 0533 QGroupBox* groupBox = new QGroupBox(i18n("Manage Templates"), frame); 0534 l->addWidget(groupBox); 0535 QVBoxLayout* vlay = new QVBoxLayout(groupBox); 0536 groupBox->setLayout(vlay); 0537 0538 QWidget* box1 = new QWidget(groupBox); 0539 QHBoxLayout* box1HBoxLayout = new QHBoxLayout(box1); 0540 box1HBoxLayout->setMargin(0); 0541 vlay->addWidget(box1); 0542 box1HBoxLayout->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); 0543 0544 QPushButton* b1 = new QPushButton(i18n("Install..."), box1); 0545 box1HBoxLayout->addWidget(b1); 0546 b1->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); 0547 connect(b1, &QAbstractButton::clicked, this, &ConfigDialog::slotInstallTemplate); 0548 whats = i18n("Click to install a new template directly."); 0549 b1->setWhatsThis(whats); 0550 0551 QPushButton* b2 = new QPushButton(i18n("Download..."), box1); 0552 box1HBoxLayout->addWidget(b2); 0553 b2->setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff"))); 0554 connect(b2, &QAbstractButton::clicked, this, &ConfigDialog::slotDownloadTemplate); 0555 whats = i18n("Click to download additional templates."); 0556 b2->setWhatsThis(whats); 0557 0558 QPushButton* b3 = new QPushButton(i18n("Delete..."), box1); 0559 box1HBoxLayout->addWidget(b3); 0560 b3->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0561 connect(b3, &QAbstractButton::clicked, this, &ConfigDialog::slotDeleteTemplate); 0562 whats = i18n("Click to select and remove installed templates."); 0563 b3->setWhatsThis(whats); 0564 0565 // stretch to fill lower area 0566 l->addStretch(1); 0567 0568 // purely for aesthetics make all widgets line up 0569 QList<QWidget*> widgets; 0570 widgets.append(m_fontCombo); 0571 widgets.append(m_fontSizeInput); 0572 widgets.append(m_baseColorCombo); 0573 widgets.append(m_textColorCombo); 0574 widgets.append(m_highBaseColorCombo); 0575 widgets.append(m_highTextColorCombo); 0576 int w = 0; 0577 foreach(QWidget* widget, widgets) { 0578 widget->ensurePolished(); 0579 w = qMax(w, widget->sizeHint().width()); 0580 } 0581 foreach(QWidget* widget, widgets) { 0582 widget->setMinimumWidth(w); 0583 } 0584 0585 KAcceleratorManager::manage(frame); 0586 m_initializedPages |= Template; 0587 readTemplateConfig(); 0588 } 0589 0590 void ConfigDialog::setupFetchPage() { 0591 QFrame* frame = new QFrame(this); 0592 KPageWidgetItem* page = new KPageWidgetItem(frame, i18n("Data Sources")); 0593 page->setHeader(i18n("Data Sources Options")); 0594 page->setIcon(QIcon::fromTheme(QStringLiteral("network-wired"))); 0595 addPage(page); 0596 } 0597 0598 void ConfigDialog::initFetchPage(QFrame* frame) { 0599 QHBoxLayout* l = new QHBoxLayout(frame); 0600 0601 QVBoxLayout* leftLayout = new QVBoxLayout(); 0602 l->addLayout(leftLayout); 0603 m_sourceListWidget = new QListWidget(frame); 0604 m_sourceListWidget->setSortingEnabled(false); // no sorting 0605 m_sourceListWidget->setSelectionMode(QAbstractItemView::SingleSelection); 0606 leftLayout->addWidget(m_sourceListWidget, 1); 0607 connect(m_sourceListWidget, &QListWidget::currentItemChanged, this, &ConfigDialog::slotSelectedSourceChanged); 0608 connect(m_sourceListWidget, &QListWidget::itemDoubleClicked, this, &ConfigDialog::slotModifySourceClicked); 0609 0610 QWidget* hb = new QWidget(frame); 0611 QHBoxLayout* hbHBoxLayout = new QHBoxLayout(hb); 0612 hbHBoxLayout->setMargin(0); 0613 leftLayout->addWidget(hb); 0614 m_moveUpSourceBtn = new QPushButton(i18n("Move &Up"), hb); 0615 hbHBoxLayout->addWidget(m_moveUpSourceBtn); 0616 m_moveUpSourceBtn->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); 0617 m_moveUpSourceBtn->setWhatsThis(i18n("The order of the data sources sets the order " 0618 "that Tellico uses when entries are automatically updated.")); 0619 m_moveDownSourceBtn = new QPushButton(i18n("Move &Down"), hb); 0620 hbHBoxLayout->addWidget(m_moveDownSourceBtn); 0621 m_moveDownSourceBtn->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); 0622 m_moveDownSourceBtn->setWhatsThis(i18n("The order of the data sources sets the order " 0623 "that Tellico uses when entries are automatically updated.")); 0624 0625 QWidget* hb2 = new QWidget(frame); 0626 QHBoxLayout* hb2HBoxLayout = new QHBoxLayout(hb2); 0627 hb2HBoxLayout->setMargin(0); 0628 leftLayout->addWidget(hb2); 0629 m_cbFilterSource = new QCheckBox(i18n("Filter by type:"), hb2); 0630 hb2HBoxLayout->addWidget(m_cbFilterSource); 0631 connect(m_cbFilterSource, &QAbstractButton::clicked, this, &ConfigDialog::slotSourceFilterChanged); 0632 m_sourceTypeCombo = new GUI::CollectionTypeCombo(hb2); 0633 hb2HBoxLayout->addWidget(m_sourceTypeCombo); 0634 void (QComboBox::* currentIndexChanged)(int) = &QComboBox::currentIndexChanged; 0635 connect(m_sourceTypeCombo, currentIndexChanged, this, &ConfigDialog::slotSourceFilterChanged); 0636 // we want to remove the item for a custom collection 0637 int index = m_sourceTypeCombo->findData(Data::Collection::Base); 0638 if(index > -1) { 0639 m_sourceTypeCombo->removeItem(index); 0640 } 0641 // disable until check box is checked 0642 m_sourceTypeCombo->setEnabled(false); 0643 0644 // these icons are rather arbitrary, but seem to vaguely fit 0645 QVBoxLayout* vlay = new QVBoxLayout(); 0646 l->addLayout(vlay); 0647 QPushButton* newSourceBtn = new QPushButton(i18n("&New..."), frame); 0648 newSourceBtn->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); 0649 newSourceBtn->setWhatsThis(i18n("Click to add a new data source.")); 0650 m_modifySourceBtn = new QPushButton(i18n("&Modify..."), frame); 0651 m_modifySourceBtn->setIcon(QIcon::fromTheme(QStringLiteral("network-wired"))); 0652 m_modifySourceBtn->setWhatsThis(i18n("Click to modify the selected data source.")); 0653 m_removeSourceBtn = new QPushButton(i18n("&Delete"), frame); 0654 m_removeSourceBtn->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); 0655 m_removeSourceBtn->setWhatsThis(i18n("Click to delete the selected data source.")); 0656 m_newStuffBtn = new QPushButton(i18n("Download..."), frame); 0657 m_newStuffBtn->setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff"))); 0658 m_newStuffBtn->setWhatsThis(i18n("Click to download additional data sources.")); 0659 // TODO: disable button for now since checksum and signature checking are no longer possible with khotnewstuff 0660 m_newStuffBtn->setEnabled(false); 0661 0662 vlay->addWidget(newSourceBtn); 0663 vlay->addWidget(m_modifySourceBtn); 0664 vlay->addWidget(m_removeSourceBtn); 0665 // separate newstuff button from the rest 0666 vlay->addSpacing(16); 0667 vlay->addWidget(m_newStuffBtn); 0668 vlay->addStretch(1); 0669 0670 connect(newSourceBtn, &QAbstractButton::clicked, this, &ConfigDialog::slotNewSourceClicked); 0671 connect(m_modifySourceBtn, &QAbstractButton::clicked, this, &ConfigDialog::slotModifySourceClicked); 0672 connect(m_moveUpSourceBtn, &QAbstractButton::clicked, this, &ConfigDialog::slotMoveUpSourceClicked); 0673 connect(m_moveDownSourceBtn, &QAbstractButton::clicked, this, &ConfigDialog::slotMoveDownSourceClicked); 0674 connect(m_removeSourceBtn, &QAbstractButton::clicked, this, &ConfigDialog::slotRemoveSourceClicked); 0675 connect(m_newStuffBtn, &QAbstractButton::clicked, this, &ConfigDialog::slotNewStuffClicked); 0676 0677 KAcceleratorManager::manage(frame); 0678 m_initializedPages |= Fetch; 0679 readFetchConfig(); 0680 } 0681 0682 void ConfigDialog::readGeneralConfig() { 0683 m_modifying = true; 0684 0685 m_cbShowTipDay->setChecked(Config::showTipOfDay()); 0686 m_cbOpenLastFile->setChecked(Config::reopenLastFile()); 0687 #ifdef ENABLE_WEBCAM 0688 m_cbEnableWebcam->setChecked(Config::enableWebcam()); 0689 #else 0690 m_cbEnableWebcam->setChecked(false); 0691 m_cbEnableWebcam->setEnabled(false); 0692 #endif 0693 0694 switch(Config::imageLocation()) { 0695 case Config::ImagesInFile: m_rbImageInFile->setChecked(true); break; 0696 case Config::ImagesInAppDir: m_rbImageInAppDir->setChecked(true); break; 0697 case Config::ImagesInLocalDir: m_rbImageInLocalDir->setChecked(true); break; 0698 } 0699 0700 bool autoCapitals = Config::autoCapitalization(); 0701 m_cbCapitalize->setChecked(autoCapitals); 0702 0703 bool autoFormat = Config::autoFormat(); 0704 m_cbFormat->setChecked(autoFormat); 0705 0706 const QRegularExpression comma(QLatin1String("\\s*,\\s*")); 0707 0708 m_leCapitals->setText(Config::noCapitalizationString().replace(comma, FieldFormat::delimiterString())); 0709 m_leArticles->setText(Config::articlesString().replace(comma, FieldFormat::delimiterString())); 0710 m_leSuffixes->setText(Config::nameSuffixesString().replace(comma, FieldFormat::delimiterString())); 0711 m_lePrefixes->setText(Config::surnamePrefixesString().replace(comma, FieldFormat::delimiterString())); 0712 0713 m_modifying = false; 0714 } 0715 0716 void ConfigDialog::readPrintingConfig() { 0717 m_modifying = true; 0718 0719 m_cbPrintHeaders->setChecked(Config::printFieldHeaders()); 0720 m_cbPrintFormatted->setChecked(Config::printFormatted()); 0721 m_cbPrintGrouped->setChecked(Config::printGrouped()); 0722 m_imageWidthBox->setValue(Config::maxImageWidth()); 0723 m_imageHeightBox->setValue(Config::maxImageHeight()); 0724 0725 m_modifying = false; 0726 } 0727 0728 void ConfigDialog::readTemplateConfig() { 0729 m_modifying = true; 0730 0731 // entry template selection 0732 const int collType = Kernel::self()->collectionType(); 0733 QString file = Config::templateName(collType); 0734 file.replace(QLatin1Char('_'), QLatin1Char(' ')); 0735 QString fileContext = file + QLatin1String(" XSL Template"); 0736 m_templateCombo->setCurrentItem(i18nc(fileContext.toUtf8().constData(), file.toUtf8().constData())); 0737 0738 m_fontCombo->setCurrentFont(QFont(Config::templateFont(collType).family())); 0739 m_fontSizeInput->setValue(Config::templateFont(collType).pointSize()); 0740 m_baseColorCombo->setColor(Config::templateBaseColor(collType)); 0741 m_textColorCombo->setColor(Config::templateTextColor(collType)); 0742 m_highBaseColorCombo->setColor(Config::templateHighlightedBaseColor(collType)); 0743 m_highTextColorCombo->setColor(Config::templateHighlightedTextColor(collType)); 0744 0745 m_modifying = false; 0746 } 0747 0748 void ConfigDialog::readFetchConfig() { 0749 m_modifying = true; 0750 0751 m_sourceListWidget->clear(); 0752 m_configWidgets.clear(); 0753 0754 m_sourceListWidget->setUpdatesEnabled(false); 0755 foreach(Fetch::Fetcher::Ptr fetcher, Fetch::Manager::self()->fetchers()) { 0756 Fetch::FetcherInfo info(fetcher->type(), fetcher->source(), 0757 fetcher->updateOverwrite(), fetcher->uuid()); 0758 FetcherInfoListItem* item = new FetcherInfoListItem(m_sourceListWidget, info); 0759 item->setFetcher(fetcher.data()); 0760 } 0761 m_sourceListWidget->setUpdatesEnabled(true); 0762 0763 if(m_sourceListWidget->count() == 0) { 0764 m_modifySourceBtn->setEnabled(false); 0765 m_removeSourceBtn->setEnabled(false); 0766 } else { 0767 // go ahead and select the first one 0768 m_sourceListWidget->setCurrentItem(m_sourceListWidget->item(0)); 0769 } 0770 0771 m_modifying = false; 0772 QTimer::singleShot(500, this, &ConfigDialog::slotCreateConfigWidgets); 0773 } 0774 0775 void ConfigDialog::saveConfiguration() { 0776 if(isPageInitialized(General)) saveGeneralConfig(); 0777 if(isPageInitialized(Printing)) savePrintingConfig(); 0778 if(isPageInitialized(Template)) saveTemplateConfig(); 0779 if(isPageInitialized(Fetch)) saveFetchConfig(); 0780 } 0781 0782 void ConfigDialog::saveGeneralConfig() { 0783 Config::setShowTipOfDay(m_cbShowTipDay->isChecked()); 0784 Config::setEnableWebcam(m_cbEnableWebcam->isChecked()); 0785 0786 int imageLocation; 0787 if(m_rbImageInFile->isChecked()) { 0788 imageLocation = Config::ImagesInFile; 0789 } else if(m_rbImageInAppDir->isChecked()) { 0790 imageLocation = Config::ImagesInAppDir; 0791 } else { 0792 imageLocation = Config::ImagesInLocalDir; 0793 } 0794 Config::setImageLocation(imageLocation); 0795 Config::setReopenLastFile(m_cbOpenLastFile->isChecked()); 0796 0797 Config::setAutoCapitalization(m_cbCapitalize->isChecked()); 0798 Config::setAutoFormat(m_cbFormat->isChecked()); 0799 0800 const QRegularExpression semicolon(QLatin1String("\\s*;\\s*")); 0801 const QChar comma = QLatin1Char(','); 0802 0803 Config::setNoCapitalizationString(m_leCapitals->text().replace(semicolon, comma)); 0804 Config::setArticlesString(m_leArticles->text().replace(semicolon, comma)); 0805 Config::setNameSuffixesString(m_leSuffixes->text().replace(semicolon, comma)); 0806 Config::setSurnamePrefixesString(m_lePrefixes->text().replace(semicolon, comma)); 0807 } 0808 0809 void ConfigDialog::savePrintingConfig() { 0810 Config::setPrintFieldHeaders(m_cbPrintHeaders->isChecked()); 0811 Config::setPrintFormatted(m_cbPrintFormatted->isChecked()); 0812 Config::setPrintGrouped(m_cbPrintGrouped->isChecked()); 0813 Config::setMaxImageWidth(m_imageWidthBox->value()); 0814 Config::setMaxImageHeight(m_imageHeightBox->value()); 0815 } 0816 0817 void ConfigDialog::saveTemplateConfig() { 0818 const int collType = Kernel::self()->collectionType(); 0819 Config::setTemplateName(collType, m_templateCombo->currentData().toString()); 0820 QFont font(m_fontCombo->currentFont().family(), m_fontSizeInput->value()); 0821 Config::setTemplateFont(collType, font); 0822 Config::setTemplateBaseColor(collType, m_baseColorCombo->color()); 0823 Config::setTemplateTextColor(collType, m_textColorCombo->color()); 0824 Config::setTemplateHighlightedBaseColor(collType, m_highBaseColorCombo->color()); 0825 Config::setTemplateHighlightedTextColor(collType, m_highTextColorCombo->color()); 0826 } 0827 0828 void ConfigDialog::saveFetchConfig() { 0829 // first, tell config widgets they got deleted 0830 foreach(Fetch::ConfigWidget* widget, m_removedConfigWidgets) { 0831 widget->removed(); 0832 } 0833 m_removedConfigWidgets.clear(); 0834 0835 bool reloadFetchers = false; 0836 int count = 0; // start group numbering at 0 0837 for( ; count < m_sourceListWidget->count(); ++count) { 0838 FetcherInfoListItem* item = static_cast<FetcherInfoListItem*>(m_sourceListWidget->item(count)); 0839 Fetch::ConfigWidget* cw = m_configWidgets[item]; 0840 if(!cw || (!cw->shouldSave() && !item->isNewSource())) { 0841 continue; 0842 } 0843 m_newStuffConfigWidgets.removeAll(cw); 0844 QString group = QStringLiteral("Data Source %1").arg(count); 0845 // in case we later change the order, clear the group now 0846 KSharedConfig::openConfig()->deleteGroup(group); 0847 KConfigGroup configGroup(KSharedConfig::openConfig(), group); 0848 configGroup.writeEntry("Name", item->data(Qt::DisplayRole).toString()); 0849 configGroup.writeEntry("Type", int(item->fetchType())); 0850 configGroup.writeEntry("UpdateOverwrite", item->updateOverwrite()); 0851 configGroup.writeEntry("Uuid", item->uuid()); 0852 cw->saveConfig(configGroup); 0853 item->setNewSource(false); 0854 // in case the ordering changed 0855 item->setConfigGroup(configGroup); 0856 reloadFetchers = true; 0857 } 0858 // now update total number of sources 0859 KConfigGroup sourceGroup(KSharedConfig::openConfig(), "Data Sources"); 0860 sourceGroup.writeEntry("Sources Count", count); 0861 // and purge old config groups 0862 QString group = QStringLiteral("Data Source %1").arg(count); 0863 while(KSharedConfig::openConfig()->hasGroup(group)) { 0864 KSharedConfig::openConfig()->deleteGroup(group); 0865 ++count; 0866 group = QStringLiteral("Data Source %1").arg(count); 0867 } 0868 0869 Config::self()->save(); 0870 0871 if(reloadFetchers) { 0872 Fetch::Manager::self()->loadFetchers(); 0873 Controller::self()->updatedFetchers(); 0874 // reload fetcher items if OK was not clicked 0875 // meaning apply was clicked 0876 if(!m_okClicked) { 0877 QString currentSource; 0878 if(m_sourceListWidget->currentItem()) { 0879 currentSource = m_sourceListWidget->currentItem()->data(Qt::DisplayRole).toString(); 0880 } 0881 readFetchConfig(); 0882 if(!currentSource.isEmpty()) { 0883 QList<QListWidgetItem*> items = m_sourceListWidget->findItems(currentSource, Qt::MatchExactly); 0884 if(!items.isEmpty()) { 0885 m_sourceListWidget->setCurrentItem(items.first()); 0886 m_sourceListWidget->scrollToItem(items.first()); 0887 } 0888 } 0889 } 0890 } 0891 } 0892 0893 void ConfigDialog::slotModified() { 0894 if(m_modifying) { 0895 return; 0896 } 0897 button(QDialogButtonBox::Ok)->setEnabled(true); 0898 button(QDialogButtonBox::Apply)->setEnabled(true); 0899 } 0900 0901 void ConfigDialog::slotNewSourceClicked() { 0902 FetcherConfigDialog dlg(this); 0903 if(dlg.exec() != QDialog::Accepted) { 0904 return; 0905 } 0906 0907 Fetch::Type type = dlg.sourceType(); 0908 if(type == Fetch::Unknown) { 0909 return; 0910 } 0911 0912 Fetch::FetcherInfo info(type, dlg.sourceName(), dlg.updateOverwrite()); 0913 FetcherInfoListItem* item = new FetcherInfoListItem(m_sourceListWidget, info); 0914 m_sourceListWidget->scrollToItem(item); 0915 m_sourceListWidget->setCurrentItem(item); 0916 Fetch::ConfigWidget* cw = dlg.configWidget(); 0917 if(cw) { 0918 cw->setAccepted(true); 0919 cw->slotSetModified(); 0920 cw->setParent(this); // keep the config widget around 0921 m_configWidgets.insert(item, cw); 0922 } 0923 m_modifySourceBtn->setEnabled(true); 0924 m_removeSourceBtn->setEnabled(true); 0925 slotModified(); // toggle apply button 0926 } 0927 0928 void ConfigDialog::slotModifySourceClicked() { 0929 FetcherInfoListItem* item = static_cast<FetcherInfoListItem*>(m_sourceListWidget->currentItem()); 0930 if(!item || !item->fetcher()) { 0931 return; 0932 } 0933 0934 Fetch::ConfigWidget* cw = nullptr; 0935 if(m_configWidgets.contains(item)) { 0936 cw = m_configWidgets[item]; 0937 } else { 0938 // grab the config widget, taking ownership 0939 cw = item->fetcher()->configWidget(this); 0940 if(cw) { // might return 0 when no widget available for fetcher type 0941 m_configWidgets.insert(item, cw); 0942 // there's weird layout bug if it's not hidden 0943 cw->hide(); 0944 } 0945 } 0946 if(!cw) { 0947 // no config widget for this one 0948 // might be because support was compiled out 0949 myDebug() << "no config widget for source" << item->data(Qt::DisplayRole).toString(); 0950 return; 0951 } 0952 FetcherConfigDialog dlg(item->data(Qt::DisplayRole).toString(), item->fetchType(), item->updateOverwrite(), cw, this); 0953 0954 if(dlg.exec() == QDialog::Accepted) { 0955 cw->setAccepted(true); // mark to save 0956 QString newName = dlg.sourceName(); 0957 if(newName != item->data(Qt::DisplayRole).toString()) { 0958 item->setData(Qt::DisplayRole, newName); 0959 cw->slotSetModified(); 0960 } 0961 item->setUpdateOverwrite(dlg.updateOverwrite()); 0962 slotModified(); // toggle apply button 0963 } 0964 cw->setParent(this); // keep the config widget around 0965 } 0966 0967 void ConfigDialog::slotRemoveSourceClicked() { 0968 FetcherInfoListItem* item = static_cast<FetcherInfoListItem*>(m_sourceListWidget->currentItem()); 0969 if(!item) { 0970 return; 0971 } 0972 0973 Tellico::NewStuff::Manager::self()->removeScriptByName(item->text()); 0974 0975 Fetch::ConfigWidget* cw = m_configWidgets[item]; 0976 if(cw) { 0977 m_removedConfigWidgets.append(cw); 0978 // it gets deleted by the parent 0979 } 0980 m_configWidgets.remove(item); 0981 delete item; 0982 // m_sourceListWidget->setCurrentItem(m_sourceListWidget->currentItem()); 0983 slotModified(); // toggle apply button 0984 } 0985 0986 void ConfigDialog::slotMoveUpSourceClicked() { 0987 int row = m_sourceListWidget->currentRow(); 0988 if(row < 1) { 0989 return; 0990 } 0991 QListWidgetItem* item = m_sourceListWidget->takeItem(row); 0992 m_sourceListWidget->insertItem(row-1, item); 0993 m_sourceListWidget->setCurrentItem(item); 0994 slotModified(); // toggle apply button 0995 } 0996 0997 void ConfigDialog::slotMoveDownSourceClicked() { 0998 int row = m_sourceListWidget->currentRow(); 0999 if(row > m_sourceListWidget->count()-2) { 1000 return; 1001 } 1002 QListWidgetItem* item = m_sourceListWidget->takeItem(row); 1003 m_sourceListWidget->insertItem(row+1, item); 1004 m_sourceListWidget->setCurrentItem(item); 1005 slotModified(); // toggle apply button 1006 } 1007 1008 void ConfigDialog::slotSourceFilterChanged() { 1009 m_sourceTypeCombo->setEnabled(m_cbFilterSource->isChecked()); 1010 const bool showAll = !m_sourceTypeCombo->isEnabled(); 1011 const int type = m_sourceTypeCombo->currentType(); 1012 for(int count = 0; count < m_sourceListWidget->count(); ++count) { 1013 FetcherInfoListItem* item = static_cast<FetcherInfoListItem*>(m_sourceListWidget->item(count)); 1014 item->setHidden(!showAll && item->fetcher() && !item->fetcher()->canFetch(type)); 1015 } 1016 } 1017 1018 void ConfigDialog::slotSelectedSourceChanged(QListWidgetItem* item_) { 1019 int row = m_sourceListWidget->row(item_); 1020 m_moveUpSourceBtn->setEnabled(row > 0); 1021 m_moveDownSourceBtn->setEnabled(row < m_sourceListWidget->count()-1); 1022 } 1023 1024 void ConfigDialog::slotNewStuffClicked() { 1025 #ifdef ENABLE_KNEWSTUFF3 1026 KNS3::DownloadDialog dialog(QStringLiteral("tellico-script.knsrc"), this); 1027 dialog.exec(); 1028 1029 KNS3::Entry::List entries = dialog.installedEntries(); 1030 if(!entries.isEmpty()) { 1031 Fetch::Manager::self()->loadFetchers(); 1032 readFetchConfig(); 1033 } 1034 #endif 1035 } 1036 1037 Tellico::FetcherInfoListItem* ConfigDialog::findItem(const QString& path_) const { 1038 if(path_.isEmpty()) { 1039 myDebug() << "empty path"; 1040 return nullptr; 1041 } 1042 1043 // this is a bit ugly, loop over all items, find the execexternal one 1044 // that matches the path 1045 for(int i = 0; i < m_sourceListWidget->count(); ++i) { 1046 FetcherInfoListItem* item = static_cast<FetcherInfoListItem*>(m_sourceListWidget->item(i)); 1047 if(item->fetchType() != Fetch::ExecExternal) { 1048 continue; 1049 } 1050 Fetch::ExecExternalFetcher* f = dynamic_cast<Fetch::ExecExternalFetcher*>(item->fetcher()); 1051 if(f && f->execPath() == path_) { 1052 return item; 1053 } 1054 } 1055 myDebug() << "no matching item found"; 1056 return nullptr; 1057 } 1058 1059 void ConfigDialog::slotShowTemplatePreview() { 1060 GUI::PreviewDialog* dlg = new GUI::PreviewDialog(this); 1061 1062 const QString templateName = m_templateCombo->currentData().toString(); 1063 dlg->setXSLTFile(templateName + QLatin1String(".xsl")); 1064 1065 StyleOptions options; 1066 options.fontFamily = m_fontCombo->currentFont().family(); 1067 options.fontSize = m_fontSizeInput->value(); 1068 options.baseColor = m_baseColorCombo->color(); 1069 options.textColor = m_textColorCombo->color(); 1070 options.highlightedTextColor = m_highTextColorCombo->color(); 1071 options.highlightedBaseColor = m_highBaseColorCombo->color(); 1072 dlg->setXSLTOptions(Kernel::self()->collectionType(), options); 1073 1074 Data::CollPtr c = CollectionFactory::collection(Kernel::self()->collectionType(), true); 1075 Data::EntryPtr e(new Data::Entry(c)); 1076 foreach(Data::FieldPtr f, c->fields()) { 1077 if(f->name() == QLatin1String("title")) { 1078 e->setField(f->name(), m_templateCombo->currentText()); 1079 } else if(f->type() == Data::Field::Image) { 1080 continue; 1081 } else if(f->type() == Data::Field::Choice) { 1082 e->setField(f->name(), f->allowed().front()); 1083 } else if(f->type() == Data::Field::Number) { 1084 e->setField(f->name(), QStringLiteral("1")); 1085 } else if(f->type() == Data::Field::Bool) { 1086 e->setField(f->name(), QStringLiteral("true")); 1087 } else if(f->type() == Data::Field::Rating) { 1088 e->setField(f->name(), QStringLiteral("5")); 1089 } else { 1090 e->setField(f->name(), f->title()); 1091 } 1092 } 1093 1094 dlg->showEntry(e); 1095 dlg->show(); 1096 // dlg gets deleted by itself 1097 // the finished() signal is connected in its constructor to delayedDestruct 1098 } 1099 1100 void ConfigDialog::loadTemplateList() { 1101 QStringList files = Tellico::locateAllFiles(QStringLiteral("tellico/entry-templates/*.xsl")); 1102 QMap<QString, QString> templates; // a QMap will have them values sorted by key 1103 foreach(const QString& file, files) { 1104 QFileInfo fi(file); 1105 QString lfile = fi.fileName().section(QLatin1Char('.'), 0, -2); 1106 QString name = lfile; 1107 name.replace(QLatin1Char('_'), QLatin1Char(' ')); 1108 QString title = i18nc((name + QLatin1String(" XSL Template")).toUtf8().constData(), name.toUtf8().constData()); 1109 templates.insert(title, lfile); 1110 } 1111 1112 QString s = m_templateCombo->currentText(); 1113 m_templateCombo->clear(); 1114 for(auto it2 = templates.constBegin(); it2 != templates.constEnd(); ++it2) { 1115 m_templateCombo->addItem(it2.key(), it2.value()); 1116 } 1117 m_templateCombo->setCurrentItem(s); 1118 } 1119 1120 void ConfigDialog::slotInstallTemplate() { 1121 QString filter = i18n("XSL Files") + QLatin1String(" (*.xsl)") + QLatin1String(";;"); 1122 filter += i18n("Template Packages") + QLatin1String(" (*.tar.gz *.tgz)") + QLatin1String(";;"); 1123 filter += i18n("All Files") + QLatin1String(" (*)"); 1124 1125 const QString fileClass(QStringLiteral(":InstallTemplate")); 1126 const QString f = QFileDialog::getOpenFileName(this, QString(), KRecentDirs::dir(fileClass), filter); 1127 if(f.isEmpty()) { 1128 return; 1129 } 1130 KRecentDirs::add(fileClass, QFileInfo(f).dir().canonicalPath()); 1131 1132 if(Tellico::NewStuff::Manager::self()->installTemplate(f)) { 1133 loadTemplateList(); 1134 } 1135 } 1136 1137 void ConfigDialog::slotDownloadTemplate() { 1138 #ifdef ENABLE_KNEWSTUFF3 1139 KNS3::DownloadDialog dialog(QStringLiteral("tellico-template.knsrc"), this); 1140 dialog.exec(); 1141 1142 KNS3::Entry::List entries = dialog.installedEntries(); 1143 if(!entries.isEmpty()) { 1144 loadTemplateList(); 1145 } 1146 #endif 1147 } 1148 1149 void ConfigDialog::slotDeleteTemplate() { 1150 bool ok; 1151 QString name = QInputDialog::getItem(this, 1152 i18n("Delete Template"), 1153 i18n("Select template to delete:"), 1154 Tellico::NewStuff::Manager::self()->userTemplates().keys(), 1155 0, false, &ok); 1156 if(ok && !name.isEmpty()) { 1157 Tellico::NewStuff::Manager::self()->removeTemplateByName(name); 1158 loadTemplateList(); 1159 } 1160 } 1161 1162 void ConfigDialog::slotCreateConfigWidgets() { 1163 for(int count = 0; count < m_sourceListWidget->count(); ++count) { 1164 FetcherInfoListItem* item = static_cast<FetcherInfoListItem*>(m_sourceListWidget->item(count)); 1165 // only create a new config widget if we don't have one already 1166 if(!m_configWidgets.contains(item) && item->fetcher()) { 1167 Fetch::ConfigWidget* cw = item->fetcher()->configWidget(this); 1168 if(cw) { // might return 0 when no widget available for fetcher type 1169 m_configWidgets.insert(item, cw); 1170 // there's weird layout bug if it's not hidden 1171 cw->hide(); 1172 } 1173 } 1174 } 1175 }