Alkimia API

alkonlinequoteswidget.cpp
1/*
2 SPDX-FileCopyrightText: 2004-2019 Thomas Baumgart tbaumgart @kde.org
3
4 This file is part of libalkimia.
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "alkonlinequoteswidget.h"
10
11#include "alkdebug.h"
12#include "alknewstuffwidget.h"
13#include "alkonlinequote.h"
14#include "alkonlinequotesmodel.h"
15#include "alkonlinequotesource.h"
16#include "alkonlinequotesprofile.h"
17#include "alkonlinequotesprofilemanager.h"
18#include "alkonlinequoteuploaddialog.h"
19#include "alkwebpage.h"
20#include "alkwebview.h"
21
22#include <QCheckBox>
23#include <QClipboard>
24#include <QDesktopServices>
25#include <QKeyEvent>
26#include <QSortFilterProxyModel>
27#include <QTreeView>
28#include <QTreeWidget>
29#include <QTreeWidgetItem>
30
31#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
32#include <KIconLoader>
33#include <KMessageWidget>
34#include <QIcon>
35#define KIcon QIcon
36#else
37#include <KComponentData>
38#include <KIcon>
39#include <KIconLoader>
40#endif
41
42#if QT_VERSION > QT_VERSION_CHECK(5, 0, 0)
43#include <QLocale>
44#define initLocale() QLocale()
45#else
46#include <KGlobal>
47#define initLocale() KGlobal::locale()
48#endif
49
50#include <KMessageBox>
51
52#include <ui_alkonlinequotedetails.h>
53#include <ui_alkonlinequoteslist.h>
54#include <ui_alkonlinequotesdebug.h>
55#include <ui_alkonlinequotesprofiledetails.h>
56#include <ui_alkonlinequotesprofiles.h>
57
58#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
59#include <klocale.h>
60static KLocale _locale(TRANSLATION_DOMAIN);
61#define i18nc(context, text) ki18nc(context, text).toString(&_locale)
62#define i18n(text) ki18n(text).toString(&_locale)
63#define tr2i18n(text, context) ki18nc(context, text).toString(&_locale)
64#endif
65
66class AlkOnlineQuotesWidget::Private
67 : public QWidget
68 , public Ui::AlkOnlineQuoteDetailsWidget
69 , public Ui::AlkOnlineQuotesDebugWidget
70 , public Ui::AlkOnlineQuotesProfileDetailsWidget
71 , public Ui::AlkOnlineQuotesProfilesWidget
72 , public Ui::AlkOnlineQuotesListWidget
73{
75public:
76 QString m_acceptLanguage;
77 QList<AlkOnlineQuoteSource> m_resetList;
78 AlkOnlineQuoteSource m_currentItem;
79 bool m_quoteInEditing;
80 AlkOnlineQuotesProfile *m_profile;
81 AlkWebView *m_webView;
82 bool m_showProfiles;
83 bool m_showUpload;
84 bool m_ghnsEditable;
85 bool m_disableUpdate;
86 QPixmap m_emptyIcon;
87 QPixmap m_inWorkIcon;
88 QPixmap m_okIcon;
89 QPixmap m_failIcon;
90 QPixmap m_unknownIcon;
91 QDialog *m_webPageDialog;
92#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
93 KMessageWidget* m_infoMessage;
94#endif
95 AlkOnlineQuotesModel *m_model;
96 AlkOnlineQuotesWidget *m_p;
97 AlkOnlineQuote m_quote;
98
99 Private(bool showProfiles, bool showUpload, AlkOnlineQuotesWidget *parent);
100 ~Private();
101
102public Q_SLOTS:
103 void slotNewProfile();
104 void slotDeleteProfile();
105 void slotSelectProfile();
106 void slotLoadProfile();
107
108 void slotDeleteEntry();
109 void slotDuplicateEntry();
110 void slotAcceptEntry();
111 void slotCopySettingsToClipboard();
112 void slotAddReferenceButton();
113 void slotLoadQuoteSource(const QModelIndex &index = QModelIndex());
114 void slotEntryChanged();
115 void slotNewEntry();
116 void slotCheckEntry();
117 void slotLogStatus(const QString &s);
118 void slotLogError(const QString &s);
119 void slotLogFailed(const QString &id, const QString &symbol);
120 void slotLogQuote(const QString &id, const QString &symbol, const QDate &date, double price);
121 void slotLogQuotes(const QString &id, const QString &symbol, const AlkDatePriceMap &prices);
122 void slotInstallEntries();
123 void slotResetQuotesList();
124 void slotUploadEntry();
125 void slotShowButton();
126
127public:
128 void loadProfiles();
129 void loadQuotesList(const bool updateResetList = false);
130 void clearIcons();
131 void initIcons();
132 void setupIcons(const AlkOnlineQuote::Errors &errors);
133 QString singleSymbol() const;
134 QStringList doubleSymbol() const;
135 QString expandedUrl() const;
136 void updateButtonState();
137 void setDefaultSource(QLineEdit* editWidget, const QString& sourceDefaultValue, const QString& defaultValue);
138};
139
140AlkOnlineQuotesWidget::Private::Private(bool showProfiles, bool showUpload, AlkOnlineQuotesWidget *parent)
141 : QWidget(parent)
142 , m_quoteInEditing(false)
143 , m_profile(nullptr)
144 , m_showProfiles(showProfiles)
145 , m_showUpload(showUpload)
146 , m_ghnsEditable(false)
147 , m_disableUpdate(false)
148#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
149 , m_inWorkIcon(BarIcon("view-refresh"))
150 , m_okIcon(BarIcon("dialog-ok-apply"))
151 , m_failIcon(BarIcon("dialog-cancel"))
152#else
153 , m_inWorkIcon(QIcon::fromTheme("view-refresh").pixmap(16))
154 , m_okIcon(QIcon::fromTheme("dialog-ok-apply").pixmap(16))
155 , m_failIcon(QIcon::fromTheme("dialog-cancel").pixmap(16))
156#endif
157 , m_webPageDialog(nullptr)
158
159#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
160 , m_infoMessage(nullptr)
161#endif
162 , m_model(nullptr)
163 , m_p(parent)
164{
165#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
166 static KComponentData alk(TRANSLATION_DOMAIN);
167#endif
168 Ui::AlkOnlineQuoteDetailsWidget::setupUi(parent);
169 Ui::AlkOnlineQuotesDebugWidget::setupUi(parent);
170 Ui::AlkOnlineQuotesProfileDetailsWidget::setupUi(parent);
171 Ui::AlkOnlineQuotesProfilesWidget::setupUi(parent);
172 Ui::AlkOnlineQuotesListWidget::setupUi(parent);
173
174 if (!QString(BUILD_KEY).isEmpty())
175 m_buildKey->setText(QString("<small>alkimia version: %1</small>").arg(BUILD_KEY));
176 else
177 m_buildKey->setText(QString());
178
179#ifdef BUILD_WITH_WEBENGINE
180 AlkWebView::setWebInspectorEnabled(true);
181#endif
182 initLocale();
183 m_webView = new AlkWebView;
184 m_webView->setWebPage(new AlkWebPage);
185#ifdef BUILD_WITH_WEBKIT
186 m_webView->setWebInspectorEnabled(true);
187#endif
188 AlkOnlineQuotesProfileManager::instance().setWebView(m_webView);
189 AlkOnlineQuotesProfileManager::instance().setWebPage(m_webView->webPage());
190
191 profilesGroupBox->setVisible(showProfiles);
192 profileDetailsBox->setVisible(showProfiles);
193 m_showButton->setVisible(!showProfiles && AlkOnlineQuotesProfileManager::instance().webViewEnabled());
194 m_ghnsSource->setVisible(false);
195 m_urlCheckLabel->setMinimumWidth(m_okIcon.width());
196
197 loadProfiles();
198
199#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
200 m_infoMessage = new KMessageWidget(onlineQuotesGroupBox);
201 groupBoxLayout->insertWidget(0, m_infoMessage);
202 m_infoMessage->hide();
203#endif
204
205 connect(m_newProfile, SIGNAL(clicked()), this, SLOT(slotNewProfile()));
206 connect(m_deleteProfile, SIGNAL(clicked()), this, SLOT(slotDeleteProfile()));
207 connect(m_profileList, SIGNAL(itemSelectionChanged()), this, SLOT(slotLoadProfile()));
208
209 connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(slotLoadQuoteSource()));
210 connect(m_acceptButton, SIGNAL(clicked()), this, SLOT(slotAcceptEntry()));
211 connect(m_copyButton, SIGNAL(clicked()), this, SLOT(slotCopySettingsToClipboard()));
212 connect(m_addReferenceButton, SIGNAL(clicked()), this, SLOT(slotAddReferenceButton()));
213 connect(m_newButton, SIGNAL(clicked()), this, SLOT(slotNewEntry()));
214 connect(m_resetButton, SIGNAL(clicked()), this, SLOT(slotResetQuotesList()));
215 connect(m_checkButton, SIGNAL(clicked()), this, SLOT(slotCheckEntry()));
216 connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteEntry()));
217 connect(m_duplicateButton, SIGNAL(clicked()), this, SLOT(slotDuplicateEntry()));
218 connect(m_installButton, SIGNAL(clicked()), this, SLOT(slotInstallEntries()));
219 connect(m_uploadButton, SIGNAL(clicked()), this, SLOT(slotUploadEntry()));
220
222 const int rowHeight = fm.height();
223#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
224 m_quoteSourceList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
225 m_quoteSourceList->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
226 m_quoteSourceList->verticalHeader()->setDefaultSectionSize(rowHeight);
227#else
228 m_quoteSourceList->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
229 m_quoteSourceList->verticalHeader()->setResizeMode(QHeaderView::Fixed);
230 m_quoteSourceList->verticalHeader()->setDefaultSectionSize(rowHeight);
231#endif
232 m_quoteSourceList->verticalHeader()->setVisible(false);
233 m_quoteSourceList->setShowGrid(false);
234 m_quoteSourceList->horizontalHeader()->setVisible(true);
235 m_quoteSourceList->setSortingEnabled(true);
236 m_quoteSourceList->setSelectionMode(QAbstractItemView::SingleSelection);
237 m_quoteSourceList->setSelectionBehavior(QAbstractItemView::SelectRows);
238
239 connect(m_quoteSourceList, SIGNAL(clicked(QModelIndex)), this, SLOT(slotLoadQuoteSource(QModelIndex)));
240
241 connect(m_editURL, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged()));
242 connect(m_editIdentifier, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged()));
243
244 m_editIdSelector->addItem(i18nc("@item:inlistbox Stock", "Symbol"), AlkOnlineQuoteSource::IdSelector::Symbol);
245 m_editIdSelector->addItem(i18nc("@item:inlistbox Stock", "Identification number"), AlkOnlineQuoteSource::IdSelector::IdentificationNumber);
246 m_editIdSelector->addItem(i18nc("@item:inlistbox Stock", "Name"), AlkOnlineQuoteSource::IdSelector::Name);
247 connect(m_editIdSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(slotEntryChanged()));
248
249 connect(m_editDate, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged()));
250 connect(m_editDateFormat, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged()));
251 connect(m_editDefaultId, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged()));
252
253 // TODO
254 // During the string freeze, these combo box entries cannot be moved from the UI file.
255 // However, to ensure that the list box entries are always defined in the source code,
256 // this should be done afterwards.
257#if 1
258 m_editPriceDecimalSeparator->setItemData(0, AlkOnlineQuoteSource::DecimalSeparator::Period);
259 m_editPriceDecimalSeparator->setItemData(1, AlkOnlineQuoteSource::DecimalSeparator::Comma);
260 m_editPriceDecimalSeparator->setItemData(2, AlkOnlineQuoteSource::DecimalSeparator::Legacy);
261#else
262 // m_editPriceDecimalSeparator->addItem(i18nc("@item:inlistbox Stock", "Legacy"), AlkOnlineQuoteSource::DecimalSeparator::Legacy);
263 // m_editPriceDecimalSeparator->addItem(i18nc("@item:inlistbox Stock", "Period (.)"), AlkOnlineQuoteSource::DecimalSeparator::Period);
264 // m_editPriceDecimalSeparator->addItem(i18nc("@item:inlistbox Stock", "Comma (,)"), AlkOnlineQuoteSource::DecimalSeparator::Comma);
265#endif
266 connect(m_editPriceDecimalSeparator, SIGNAL(currentIndexChanged(int)), this, SLOT(slotEntryChanged()));
267 connect(m_editPrice, SIGNAL(textChanged(QString)), this, SLOT(slotEntryChanged()));
268
269 m_editDataFormat->addItem(toString(AlkOnlineQuoteSource::DataFormat::StrippedHTML), AlkOnlineQuoteSource::DataFormat::StrippedHTML);
270 m_editDataFormat->addItem(toString(AlkOnlineQuoteSource::DataFormat::HTML), AlkOnlineQuoteSource::DataFormat::HTML);
271 m_editDataFormat->addItem(toString(AlkOnlineQuoteSource::DataFormat::CSV), AlkOnlineQuoteSource::DataFormat::CSV);
272#ifdef BUILD_WITH_WEBKIT
273 m_editDataFormat->addItem(toString(AlkOnlineQuoteSource::DataFormat::CSS), AlkOnlineQuoteSource::DataFormat::CSS);
274#endif
275 m_editDataFormat->addItem(toString(AlkOnlineQuoteSource::DataFormat::JSON), AlkOnlineQuoteSource::DataFormat::JSON);
276 connect(m_editDataFormat, SIGNAL(currentIndexChanged(int)), this, SLOT(slotEntryChanged()));
277
278 m_editDownloadType->addItem(i18nc("@item:inlistbox Stock", "Default"), AlkOnlineQuoteSource::DownloadType::Default);
279 m_editDownloadType->addItem(i18nc("@item:inlistbox Stock", "Javascript"), AlkOnlineQuoteSource::DownloadType::Javascript);
280 connect(m_editDownloadType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotEntryChanged()));
281
282 connect(m_ghnsSource, SIGNAL(toggled(bool)), this, SLOT(slotEntryChanged()));
283 connect(m_showButton, SIGNAL(clicked()), this, SLOT(slotShowButton()));
284
285 m_returnLastPriceStateComboBox->addItem(i18nc("@item:inlistbox Stock", "Off"), AlkOnlineQuote::LastPriceState::Off);
286 m_returnLastPriceStateComboBox->addItem(i18nc("@item:inlistbox Stock", "Always"), AlkOnlineQuote::LastPriceState::Always);
287 m_returnLastPriceStateComboBox->addItem(i18nc("@item:inlistbox Stock", "Always when today"), AlkOnlineQuote::LastPriceState::AlwaysWhenToday);
288 m_returnLastPriceStateComboBox->setData<AlkOnlineQuote::LastPriceState>(m_quote.returnLastPriceState());
289
290 connect(&m_quote, SIGNAL(status(QString)), this, SLOT(slotLogStatus(QString)));
291 connect(&m_quote, SIGNAL(error(QString)), this, SLOT(slotLogError(QString)));
292 connect(&m_quote, SIGNAL(failed(QString, QString)), this, SLOT(slotLogFailed(QString, QString)));
293 connect(&m_quote, SIGNAL(quote(QString, QString, QDate, double)), this, SLOT(slotLogQuote(QString, QString, QDate, double)));
294 connect(&m_quote, SIGNAL(quotes(QString, QString, AlkDatePriceMap)), this, SLOT(slotLogQuotes(QString, QString, AlkDatePriceMap)));
295
296 m_reverseSearchStateCheckBox->setChecked(m_quote.enableReverseLaunch());
297
298 m_uploadButton->setVisible(false);
299 m_acceptButton->setEnabled(false);
300 m_resetButton->setVisible(m_showProfiles);
301 slotLoadProfile();
302}
303
304AlkOnlineQuotesWidget::Private::~Private()
305{
306 // only call deleteLater if we have created the dialog
307 if (m_webPageDialog) {
308 m_webPageDialog->deleteLater();
309 }
310 delete m_webView->webPage();
311 delete m_webView;
312 delete m_model;
313}
314
315void AlkOnlineQuotesWidget::Private::loadProfiles()
316{
317 AlkOnlineQuotesProfileList list = AlkOnlineQuotesProfileManager::instance().profiles();
318 if (list.isEmpty())
319 return;
320 for (AlkOnlineQuotesProfile *profile : list) {
321 QListWidgetItem *item = new QListWidgetItem(dynamic_cast<QListWidget *>(m_profileList));
322 item->setText(profile->name());
323 item->setFlags(item->flags() | Qt::ItemIsEditable);
324 }
325 m_profileList->setCurrentRow(0);
326 m_profile = AlkOnlineQuotesProfileManager::instance().profiles().first();
327 loadQuotesList(true);
328}
329
330void AlkOnlineQuotesWidget::Private::loadQuotesList(const bool updateResetList)
331{
332 // create or update model stack
333 if (!m_model) {
334 m_model = new AlkOnlineQuotesModel(m_profile);
335 auto proxyModel = new QSortFilterProxyModel(this);
336 proxyModel->setSourceModel(m_model);
337 m_quoteSourceList->setModel(proxyModel);
338 } else {
339 m_model->setProfile(m_profile);
340 }
341
342 if (updateResetList) {
343 m_resetList.clear();
344 const QStringList groups = m_profile->quoteSources();
345
346 // Keep a copy of all loaded local entries.
347 // GHNS sources can only be maintained through the
348 // external dialog because otherwise resetConfig() would
349 // remove the GHNS file behind the scenes.
350 for (const auto& quoteSourceName : groups) {
351 const auto quoteSource = AlkOnlineQuoteSource(quoteSourceName, m_profile);
352 if (!quoteSource.isGHNS()) {
353 m_resetList.append(quoteSource);
354 }
355 }
356 }
357
358 const auto indexes = m_quoteSourceList->model()->match(m_model->index(0, 0), Qt::DisplayRole, m_currentItem.name(), 1, Qt::MatchExactly);
359 const auto index = !indexes.isEmpty() ? indexes.at(0) : QModelIndex();
360
361 m_quoteSourceList->setCurrentIndex(index);
362 m_quoteSourceList->selectRow(index.row());
363 m_quoteSourceList->scrollTo(index, QAbstractItemView::EnsureVisible);
364 slotLoadQuoteSource(m_quoteSourceList->currentIndex());
365 updateButtonState();
366}
367
368void AlkOnlineQuotesWidget::Private::slotNewProfile()
369{
370 QTreeWidgetItem *item = new QTreeWidgetItem(dynamic_cast<QTreeWidget *>(m_profileList));
371 item->setText(0, QLatin1String("new profile"));
372 item->setFlags(item->flags() | Qt::ItemIsEditable);
373}
374
375void AlkOnlineQuotesWidget::Private::slotDeleteProfile()
376{
377 delete m_profileList->currentItem();
378}
379
380void AlkOnlineQuotesWidget::Private::slotSelectProfile()
381{
382 slotLoadProfile();
383}
384
385void AlkOnlineQuotesWidget::Private::slotLoadProfile()
386{
387 m_uploadButton->setEnabled(false);
388 const AlkOnlineQuotesProfileList list = AlkOnlineQuotesProfileManager::instance().profiles();
389 if (!m_showProfiles) {
390 if (list.isEmpty())
391 return;
392 m_profile = list.first();
393 m_installButton->setVisible(m_profile->hasGHNSSupport());
394 m_uploadButton->setVisible(m_profile->hasGHNSSupport());
395 loadQuotesList(true);
396 return;
397 }
398
399 for (AlkOnlineQuotesProfile *profile : list) {
400 if (m_profileList->currentItem() && m_profileList->currentItem()->text() == profile->name()) {
401 m_profile = profile;
402 loadQuotesList(true);
403 m_installButton->setVisible(profile->hasGHNSSupport());
404 m_uploadButton->setVisible(profile->hasGHNSSupport());
405 break;
406 }
407 }
408
409 bool visible = m_profile->type() != AlkOnlineQuotesProfile::Type::None;
410 m_configFilePath->setText(m_profile->kConfigFile());
411 m_configFilePath->setVisible(visible);
412 m_configLabel->setEnabled(visible);
413
414 visible = m_profile->hasGHNSSupport();
415 m_GHNSConfigFilePath->setText(m_profile->hotNewStuffConfigFile());
416 m_GHNSConfigFilePath->setVisible(visible);
417 m_GHNSConfigLabel->setEnabled(visible);
418
419 m_GHNSDataPath->setText(m_profile->hotNewStuffReadPath().join(" "));
420 m_GHNSDataPath->setVisible(visible);
421 m_GHNSDataLabel->setEnabled(visible);
422}
423
424void AlkOnlineQuotesWidget::Private::slotLoadQuoteSource(const QModelIndex &index)
425{
426 Q_UNUSED(index)
427
428 m_quoteInEditing = false;
429
430 m_disableUpdate = true;
431 m_editURL->clear();
432 m_editIdentifier->clear();
433 m_editIdSelector->setCurrentIndex(AlkOnlineQuoteSource::IdSelector::Symbol);
434 m_editPriceDecimalSeparator->setCurrentIndex(AlkOnlineQuoteSource::DecimalSeparator::Legacy);
435 m_editPrice->clear();
436 m_editDate->clear();
437 m_editDateFormat->clear();
438 m_editDefaultId->clear();
439
440 QString name;
441 if (m_quoteSourceList->currentIndex().isValid()) {
442 name = m_quoteSourceList->model()->data(m_quoteSourceList->currentIndex(), AlkOnlineQuotesModel::NameRole).toString();
443 AlkOnlineQuoteSource source = AlkOnlineQuoteSource(name, m_profile);
444 m_currentItem = source;
445 if (source.isReference())
446 source = source.asReference();
447 m_editURL->setText(source.url());
448 m_editIdentifier->setText(source.idRegex());
449 m_editIdSelector->setData<AlkOnlineQuoteSource::IdSelector>(source.idSelector());
450 m_editPriceDecimalSeparator->setData<AlkOnlineQuoteSource::DecimalSeparator>(source.priceDecimalSeparator());
451 m_editPrice->setText(source.priceRegex());
452 m_editDataFormat->setData<AlkOnlineQuoteSource::DataFormat>(source.dataFormat());
453 m_editDate->setText(source.dateRegex());
454 m_editDateFormat->setText(source.dateFormat());
455 m_editDefaultId->setText(source.defaultId());
456 m_editDownloadType->setData<AlkOnlineQuoteSource::DownloadType>(source.downloadType());
457 m_ghnsSource->setChecked(source.isGHNS());
458 }
459
460 bool enabled = !name.isEmpty() && !m_currentItem.isReference();
461 bool isFinanceQuoteSource = (enabled && AlkOnlineQuoteSource::isFinanceQuote(name)) ||
462 m_profile->type() == AlkOnlineQuotesProfile::Type::Script;
463
464 if (isFinanceQuoteSource || (m_currentItem.isGHNS() && !m_ghnsEditable))
465 enabled = false;
466
467 m_editURL->setEnabled(enabled);
468 m_editIdentifier->setEnabled(enabled);
469 m_editIdSelector->setEnabled(enabled);
470 m_editPriceDecimalSeparator->setEnabled(enabled);
471 m_editPrice->setEnabled(enabled);
472 m_editDate->setEnabled(enabled);
473 m_editDateFormat->setEnabled(enabled);
474 m_editDefaultId->setEnabled(enabled);
475 m_editDownloadType->setEnabled(enabled);
476 m_ghnsSource->setVisible(m_profile && m_profile->hasGHNSSupport());
477 m_ghnsSource->setEnabled(m_showUpload && m_profile && m_profile->hasGHNSSupport() && enabled);
478 m_uploadButton->setEnabled(m_showUpload && m_profile && m_profile->hasGHNSSupport());
479 m_addReferenceButton->setEnabled(m_currentItem.isGHNS());
480 m_editDataFormat->setEnabled(enabled);
481
482 // tab order seems to get messed up when enabling widgets
483 // easy solution: setup the tab order again
484 QWidget::setTabOrder(m_editURL, m_editDownloadType);
485 QWidget::setTabOrder(m_editDownloadType, m_editDataFormat);
486 QWidget::setTabOrder(m_editDataFormat, m_editIdentifier);
487 QWidget::setTabOrder(m_editIdentifier, m_editIdSelector);
488 QWidget::setTabOrder(m_editIdSelector, m_editPrice);
489 QWidget::setTabOrder(m_editPrice, m_editPriceDecimalSeparator);
490 QWidget::setTabOrder(m_editPriceDecimalSeparator, m_editDate);
491 QWidget::setTabOrder(m_editDate, m_editDateFormat);
492 QWidget::setTabOrder(m_editDateFormat, m_editDefaultId);
493 QWidget::setTabOrder(m_editDefaultId, m_ghnsSource);
494 QWidget::setTabOrder(m_ghnsSource, m_acceptButton);
495 QWidget::setTabOrder(m_acceptButton, m_cancelButton);
496 QWidget::setTabOrder(m_cancelButton, m_copyButton);
497
498 m_disableUpdate = false;
499
500 updateButtonState();
501}
502
503void AlkOnlineQuotesWidget::Private::slotEntryChanged()
504{
505 if (!m_disableUpdate)
506 updateButtonState();
507}
508
509void AlkOnlineQuotesWidget::Private::updateButtonState()
510{
511 clearIcons();
512 bool modified = !m_currentItem.isReference() &&
513 (m_editURL->text() != m_currentItem.url()
514 || m_editIdentifier->text() != m_currentItem.idRegex()
515 || m_editIdSelector->currentIndex() != m_editIdSelector->findData(m_currentItem.idSelector())
516 || m_editDataFormat->currentIndex() != m_editDataFormat->findData(m_currentItem.dataFormat())
517 || m_editDate->text() != m_currentItem.dateRegex()
518 || m_editDateFormat->text() != m_currentItem.dateFormat()
519 || m_editDefaultId->text() != m_currentItem.defaultId()
520 || m_editPriceDecimalSeparator->currentIndex() != m_editPriceDecimalSeparator->findData(m_currentItem.priceDecimalSeparator())
521 || m_editDownloadType->currentIndex() != m_editDownloadType->findData(m_currentItem.downloadType())
522 || m_editPrice->text() != m_currentItem.priceRegex()
523 || m_ghnsSource->isChecked() != m_currentItem.isGHNS());
524
525 bool isFinanceQuote = m_currentItem.isFinanceQuote() || m_profile->type() == AlkOnlineQuotesProfile::Type::Script;
526 bool hasWriteSupport = (m_profile->type() != AlkOnlineQuotesProfile::Type::None && !isFinanceQuote) || m_profile->hasGHNSSupport();
527 bool isRemoteUnpublished = m_currentItem.isGHNS() && m_currentItem.profile()->GHNSFilePath(m_currentItem.name()).isEmpty();
528 bool isDefaultSource = m_profile->defaultQuoteSources().contains(m_currentItem.name());
529 m_newButton->setEnabled(hasWriteSupport);
530 m_cancelButton->setEnabled(modified);
531 m_duplicateButton->setEnabled(hasWriteSupport);
532 m_deleteButton->setEnabled((!m_currentItem.isReadOnly() && !m_currentItem.isGHNS() && !isDefaultSource) || isRemoteUnpublished);
533 m_uploadButton->setEnabled(m_profile->hasGHNSSupport() && m_currentItem.isGHNS() && AlkOnlineQuoteUploadDialog::isSupported());
534 m_acceptButton->setEnabled(modified);
535 m_checkButton->setEnabled(isFinanceQuote || !modified);
536 m_editIdSelector->setVisible(m_profile->type() == AlkOnlineQuotesProfile::Type::KMyMoney5);
537 m_editIdSelectorLabel->setVisible(m_profile->type() == AlkOnlineQuotesProfile::Type::KMyMoney5);
538
539 // debug dock widget
540 AlkOnlineQuoteSource source(m_currentItem);
541 if (source.isReference())
542 source = source.asReference();
543
544 bool hasDateRange = source.dataFormat() == AlkOnlineQuoteSource::CSV || source.dataFormat() == AlkOnlineQuoteSource::JSON;
545 m_startDateLabel->setVisible(hasDateRange);
546 m_endDateLabel->setVisible(hasDateRange);
547 m_startDateEdit->setVisible(hasDateRange);
548 m_endDateEdit->setVisible(hasDateRange);
549
550 if (source.requiresTwoIdentifier()) {
551 m_checkSymbol->setEnabled(false);
552 m_checkSymbol->setText(QString());
553 m_checkSymbol2->setEnabled(true);
554 setDefaultSource(m_checkSymbol2, source.defaultId(), "BTC GBP");
555 m_reverseSearchStateCheckBox->setVisible(true);
556 } else {
557 m_checkSymbol->setEnabled(true);
558 setDefaultSource(m_checkSymbol, source.defaultId(), "ORCL");
559 m_checkSymbol2->setEnabled(false);
560 m_checkSymbol2->setText(QString());
561 m_reverseSearchStateCheckBox->setVisible(false);
562 }
563}
564
565void AlkOnlineQuotesWidget::Private::setDefaultSource(QLineEdit* editWidget, const QString& sourceDefaultValue, const QString& defaultValue)
566{
567 QString currentValue = editWidget->text();
568 if (currentValue.isEmpty()) {
569 editWidget->setText(!sourceDefaultValue.isEmpty() ? sourceDefaultValue : defaultValue);
570 }
571}
572void AlkOnlineQuotesWidget::Private::slotDeleteEntry()
573{
574 if (!m_quoteSourceList->currentIndex().isValid())
575 return;
576
578 i18n("Are you sure to delete this online quote ?"),
579 i18n("Delete online quote"),
582 QString("DeletingOnlineQuote"));
583 if (ret == KMessageBox::Cancel) {
584 return;
585 }
586
587 // keep this order to avoid deleting the wrong current item
588 m_quoteSourceList->model()->removeRow(m_quoteSourceList->currentIndex().row());
589 // select next entry
590 slotLoadQuoteSource(m_quoteSourceList->currentIndex());
591 updateButtonState();
592}
593
594void AlkOnlineQuotesWidget::Private::slotDuplicateEntry()
595{
596 if (!m_quoteSourceList->currentIndex().isValid())
597 return;
598
599 AlkOnlineQuoteSource copy(m_currentItem);
600 copy.setName(copy.name() + i18n(".copy"));
601 copy.setGHNS(false);
602 copy.write();
603 m_currentItem = copy;
604 loadQuotesList();
605}
606
607void AlkOnlineQuotesWidget::Private::slotAcceptEntry()
608{
609 m_currentItem.setUrl(m_editURL->text());
610 m_currentItem.setIdRegex(m_editIdentifier->text());
611 m_currentItem.setIdSelector(m_editIdSelector->currentData().value<AlkOnlineQuoteSource::IdSelector>());
612 m_currentItem.setDataFormat(m_editDataFormat->currentData().value<AlkOnlineQuoteSource::DataFormat>());
613 m_currentItem.setDateRegex(m_editDate->text());
614 m_currentItem.setDateFormat(m_editDateFormat->text());
615 m_currentItem.setDefaultId(m_editDefaultId->text());
616 m_currentItem.setPriceDecimalSeparator(m_editPriceDecimalSeparator->currentData().value<AlkOnlineQuoteSource::DecimalSeparator>());
617 m_currentItem.setDownloadType(m_editDownloadType->currentData().value<AlkOnlineQuoteSource::DownloadType>());
618 m_currentItem.setPriceRegex(m_editPrice->text());
619 m_currentItem.setGHNS(m_ghnsSource->isChecked());
620 m_currentItem.write();
621 m_checkButton->setEnabled(true);
622 loadQuotesList();
623 updateButtonState();
624}
625
626void AlkOnlineQuotesWidget::Private::slotCopySettingsToClipboard()
627{
628 QClipboard* clipboard = QApplication::clipboard();
629
630 QStringList settings;
631 settings << i18nc("@title %1 is version info", "Online quote settings generated with Alkimia %1").arg(BUILD_KEY);
632 settings << QString();
633
634 settings << i18nc("@info online quote setting", "URL: %1").arg(m_editURL->text());
635 settings << i18nc("@info online quote setting", "Download mode: %1").arg(m_editDownloadType->currentText());
636 settings << i18nc("@info online quote setting", "Data format: %1").arg(m_editDataFormat->currentText());
637 settings << i18nc("@info online quote setting", "Identifier: %1").arg(m_editIdentifier->text());
638 settings << i18nc("@info online quote setting", "Select by: %1").arg(m_editIdSelector->currentText());
639 settings << i18nc("@info online quote setting", "Price: %1").arg(m_editPrice->text());
640 settings << i18nc("@info online quote setting", "Price decimal separator: %1").arg(m_editPriceDecimalSeparator->currentText());
641 settings << i18nc("@info online quote setting", "Date: %1").arg(m_editDate->text());
642 settings << i18nc("@info online quote setting", "Date format: %1").arg(m_editDateFormat->text());
643 settings << i18nc("@info online quote setting", "Default identifier: %1").arg(m_editDefaultId->text());
644 settings << i18nc("@info online quote setting", "Remote source: %1")
645 .arg(m_ghnsSource->isChecked() ? i18nc("@item:intext checkbox setting", "checked") : i18nc("@item:intext checkbox setting", "not checked"));
646
647 // force a final NL character on the last line
648 settings << QString();
649
650 clipboard->setText(settings.join(QLatin1String("\n")));
651}
652
653void AlkOnlineQuotesWidget::Private::slotAddReferenceButton()
654{
655 if (!m_quoteSourceList->currentIndex().isValid())
656 return;
657
658 QString newNameBase = m_currentItem.name() + i18nc("@item:valuesuffix to name for a quote source reference", ".reference");
659 int index = 1;
660 QString newName = newNameBase;
661 while(m_profile->quoteSources().contains(newName)) {
662 newName = QString("%1%2").arg(newNameBase).arg(index++);
663 }
664 AlkOnlineQuoteSource copy(newName, m_profile);
665 copy.setGHNS(false);
666 copy.setReferenceName(m_currentItem.name());
667 copy.write();
668 m_currentItem = copy;
669 loadQuotesList();
670}
671
672void AlkOnlineQuotesWidget::Private::slotNewEntry()
673{
674 const bool newEntries = m_profile->quoteSources().contains(i18n("New Quote Source"));
675 if (!newEntries) {
676 AlkOnlineQuoteSource newSource(i18n("New Quote Source"), m_profile);
677 newSource.write();
678 m_currentItem = newSource;
679 loadQuotesList();
680
681 } else {
682#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
683 if (!m_infoMessage->isVisible() && !m_infoMessage->isShowAnimationRunning()) {
684 m_infoMessage->resize(width(), m_infoMessage->heightForWidth(width()));
685 m_infoMessage->setText(
686 i18nc("@info Detail that only one new entry can exist at any time", "<b>New Quote Source</b> already exists."));
688 m_infoMessage->animatedShow();
689 }
690#endif
691 }
692}
693
694void AlkOnlineQuotesWidget::Private::clearIcons()
695{
696 m_urlCheckLabel->setPixmap(m_emptyIcon);
697 m_dateCheckLabel->setPixmap(m_emptyIcon);
698 m_priceCheckLabel->setPixmap(m_emptyIcon);
699 m_symbolCheckLabel->setPixmap(m_emptyIcon);
700 m_dateFormatCheckLabel->setPixmap(m_emptyIcon);
701}
702
703void AlkOnlineQuotesWidget::Private::initIcons()
704{
705 m_urlCheckLabel->setPixmap(m_inWorkIcon);
706 m_dateCheckLabel->setPixmap(m_inWorkIcon);
707 m_priceCheckLabel->setPixmap(m_inWorkIcon);
708 m_symbolCheckLabel->setPixmap(m_inWorkIcon);
709 m_dateFormatCheckLabel->setPixmap(m_inWorkIcon);
710}
711
712void AlkOnlineQuotesWidget::Private::setupIcons(const AlkOnlineQuote::Errors &errors)
713{
714 clearIcons();
715 if (errors & AlkOnlineQuote::Errors::URL) {
716 m_urlCheckLabel->setPixmap(m_failIcon);
717 } else {
718 m_urlCheckLabel->setPixmap(m_okIcon);
719 m_symbolCheckLabel->setPixmap((errors & AlkOnlineQuote::Errors::Symbol) ? m_failIcon : m_okIcon);
720 m_priceCheckLabel->setPixmap((errors & AlkOnlineQuote::Errors::Price) ? m_failIcon : m_okIcon);
721 if (errors & AlkOnlineQuote::Errors::Date) {
722 m_dateCheckLabel->setPixmap(m_failIcon);
723 } else {
724 if (m_currentItem.dateRegex().isEmpty()) {
725 m_dateCheckLabel->setPixmap(m_emptyIcon);
726 m_dateFormatCheckLabel->setPixmap(m_emptyIcon);
727 } else {
728 m_dateCheckLabel->setPixmap(m_okIcon);
729 m_dateFormatCheckLabel->setPixmap(
730 (errors & AlkOnlineQuote::Errors::DateFormat) ? m_failIcon : m_okIcon);
731 }
732 }
733 }
734}
735
736void AlkOnlineQuotesWidget::Private::slotCheckEntry()
737{
738 m_quote.setProfile(m_profile);
739 m_logWindow->setVisible(true);
740 m_logWindow->clear();
741 clearIcons();
742 m_quote.setAcceptLanguage(m_acceptLanguage);
743 m_quote.setReturnLastPriceState(m_returnLastPriceStateComboBox->currentData().value<AlkOnlineQuote::LastPriceState>());
744 m_quote.setEnableReverseLaunch(m_reverseSearchStateCheckBox->checkState() == Qt::Checked);
745 initIcons();
746
747 AlkOnlineQuoteSource source(m_currentItem);
748 if (source.isReference())
749 source = source.asReference();
750 if (source.dataFormat() == AlkOnlineQuoteSource::CSV || source.dataFormat() == AlkOnlineQuoteSource::JSON) {
751 m_quote.setDateRange(m_startDateEdit->date(), m_endDateEdit->date());
752 } else {
753 m_quote.setDateRange(QDate(), QDate());
754 }
755
756 if (source.requiresTwoIdentifier()) {
757 m_quote.launch(m_checkSymbol2->text(), m_checkSymbol2->text(), source.name());
758 } else {
759 m_quote.launch(m_checkSymbol->text(), m_checkSymbol->text(), source.name());
760 }
761 setupIcons(m_quote.errors());
762}
763
764void AlkOnlineQuotesWidget::Private::slotLogStatus(const QString &s)
765{
766 m_logWindow->append(s);
767}
768
769void AlkOnlineQuotesWidget::Private::slotLogError(const QString &s)
770{
771 slotLogStatus(QString("<font color=\"red\"><b>") + s + QString("</b></font>"));
772}
773
774void AlkOnlineQuotesWidget::Private::slotLogFailed(const QString &id, const QString &symbol)
775{
776 slotLogStatus(QString("%1 %2").arg(id, symbol));
777}
778
779void AlkOnlineQuotesWidget::Private::slotLogQuote(const QString &id, const QString &symbol,
780 const QDate &date, double price)
781{
782 slotLogStatus(QString("<font color=\"green\">%1 %2 %3 %4</font>").arg(id, symbol,
783 date.toString()).arg(
784 price));
785}
786
787void AlkOnlineQuotesWidget::Private::slotLogQuotes(const QString &id, const QString &symbol,
788 const AlkDatePriceMap &prices)
789{
790 slotLogStatus(QString("<font color=\"green\">%1 %2</font>").arg(id, symbol));
791
792 slotLogStatus(QString("<font color=\"green\">date price</font>"));
793 for (auto i = prices.constBegin(), end = prices.constEnd(); i != end; ++i) {
794 slotLogStatus(QString("<font color=\"green\">%1 %2</font>")
795 .arg(i.key().toString(Qt::ISODate)).arg(i.value().toDouble()));
796 }
797}
798
799void AlkOnlineQuotesWidget::Private::slotInstallEntries()
800{
801 QString configFile = m_profile->hotNewStuffConfigFile();
802
803 AlkNewStuffWidget widget;
804 widget.init(configFile);
805 if (widget.showInstallDialog()) {
806 m_profile->reload();
807 loadQuotesList();
808 }
809}
810
811void AlkOnlineQuotesWidget::Private::slotResetQuotesList()
812{
813 m_p->resetConfig();
814}
815
816void AlkOnlineQuotesWidget::Private::slotUploadEntry()
817{
818 QPointer<AlkOnlineQuoteUploadDialog> dialog = new AlkOnlineQuoteUploadDialog(m_currentItem, false, this);
819 dialog->exec();
820 delete dialog;
821}
822
823void AlkOnlineQuotesWidget::Private::slotShowButton()
824{
825 if (!m_webPageDialog) {
826 m_webPageDialog = new QDialog;
827 m_webPageDialog->setWindowTitle(i18n("Online Quote HTML Result Window"));
828 QVBoxLayout *layout = new QVBoxLayout;
829 layout->addWidget(m_webView);
830 m_webPageDialog->setLayout(layout);
831 }
832 m_webPageDialog->show();
833}
834
835QString AlkOnlineQuotesWidget::Private::expandedUrl() const
836{
837 AlkOnlineQuoteSource source(m_currentItem);
838 if (source.isReference())
839 source = source.asReference();
840 if (source.requiresTwoIdentifier()) {
841 return source.url().arg(m_checkSymbol2->text());
842 } else {
843 return source.url().arg(m_checkSymbol->text());
844 }
845}
846
847AlkOnlineQuotesWidget::AlkOnlineQuotesWidget(bool showProfiles, bool showUpload, QWidget *parent)
848 : QWidget(parent)
849 , d(new Private(showProfiles, showUpload, this))
850{
851}
852
853AlkOnlineQuotesWidget::~AlkOnlineQuotesWidget()
854{
855 delete d;
856}
857
858QWidget *AlkOnlineQuotesWidget::profilesWidget()
859{
860 QFrame *frame = new QFrame;
861 frame->setLayout(d->profilesGroupBox->layout());
862 return frame;
863}
864
865QWidget *AlkOnlineQuotesWidget::profileDetailsWidget()
866{
867 QFrame *frame = new QFrame;
868 frame->setLayout(d->profileDetailsBox->layout());
869 return frame;
870}
871
872QWidget *AlkOnlineQuotesWidget::onlineQuotesWidget()
873{
874 QFrame *frame = new QFrame;
875 frame->setLayout(d->onlineQuotesGroupBox->layout());
876 return frame;
877}
878
879QWidget *AlkOnlineQuotesWidget::quoteDetailsWidget()
880{
881 QFrame *frame = new QFrame;
882 frame->setLayout(d->detailsGroupBox->layout());
883 return frame;
884}
885
886QWidget *AlkOnlineQuotesWidget::debugWidget()
887{
888 QFrame *frame = new QFrame;
889 frame->setLayout(d->debugGroupBox->layout());
890 return frame;
891}
892
893void AlkOnlineQuotesWidget::readConfig()
894{
895}
896
897void AlkOnlineQuotesWidget::writeConfig()
898{
899}
900
901void AlkOnlineQuotesWidget::resetConfig()
902{
904 QStringList groups = d->m_profile->quoteSources();
905
906 // delete all currently defined entries
907 for (it = groups.constBegin(); it != groups.constEnd(); ++it) {
908 AlkOnlineQuoteSource quoteSource(*it, d->m_profile);
909 // Only remove when not a GHNS source. Those can only
910 // be removed via the external dialog. If removed here
911 // only the GHNS file will be removed and the entry
912 // shows up as empty local one when added by the logic
913 // below. Hence, the GHNS entries are not collected
914 // in the m_resetList.
915 if (!quoteSource.isGHNS()) {
916 quoteSource.remove();
917 }
918 }
919
920 // and write back the one's from the reset list
921 QList<AlkOnlineQuoteSource>::iterator itr;
922 for (itr = d->m_resetList.begin(); itr != d->m_resetList.end(); ++itr) {
923 (*itr).write();
924 }
925
926 d->loadQuotesList();
927}
928
929QString AlkOnlineQuotesWidget::acceptLanguage() const
930{
931 return d->m_acceptLanguage;
932}
933
934void AlkOnlineQuotesWidget::setAcceptLanguage(const QString &text)
935{
936 d->m_acceptLanguage = text;
937}
938
939bool AlkOnlineQuotesWidget::GHNSSourceEditable()
940{
941 return d->m_ghnsEditable;
942
943}
944
945void AlkOnlineQuotesWidget::setGHNSSourceEditable(bool state)
946{
947 d->m_ghnsEditable = state;
948}
949
950#include "alkonlinequoteswidget.moc"
Wrapper for debug output.
const QString & defaultId() const
Return the default identifier known to work.
void setDefaultId(const QString &defaultId)
Set the default identifier, which is known to work.
bool requiresTwoIdentifier() const
Return state if this source requires two identifier.
DataFormat
Supported formats of downloaded data.
bool isReference() const
Return state if this source is a reference.
DecimalSeparator
Type of decimal separator.
AlkOnlineQuoteSource asReference() const
Return referenced quote source.
DataFormat dataFormat() const
Return the format of the downloaded data.
bool isFinanceQuote() const
Checks whether the current source is of type "Finance::Quote".
void setDataFormat(DataFormat dataFormat)
Set the format of the downloaded data.
void setDateRegex(const QString &dateRegex)
Set regular expression for parsing dates.
void setAcceptLanguage(const QString &language)
Set accepted language the online quote should be returned for.
bool enableReverseLaunch()
Returns the status whether a search with swapped symbols should be performed after a query for a symb...
void setEnableReverseLaunch(bool state)
Set the status whether a search with swapped symbole should be performed after a query for a symbol r...
void setDateRange(const QDate &from, const QDate &to)
Defines a date range within which the data is to be retrieved.
bool launch(const QString &_symbol, const QString &_id, const QString &_source=QString())
This launches a web-based quote update for the given _symbol.
void setReturnLastPriceState(LastPriceState state)
Sets the status of the price to be returned for special date range.
LastPriceState returnLastPriceState()
Returns the status of the price to be returned for special date ranges.
const AlkOnlineQuote::Errors & errors()
If launch() returns false, this method can be used to get details about the errors that occurred.
LastPriceState
Supported values for returning prices in special cases.
@ AlwaysWhenToday
If the date range has the same start and end date, is identical to the current date,...
@ Always
If no price is available in the specified period, but older ones are available, the most current pric...
@ Off
No handling of special cases.
The AlkWebPage class provides an object to load and view web documents to provide functionality like ...
Definition alkwebpage.h:100
The AlkWebView class provides a widget that is used to load and display web documents.
Definition alkwebview.h:87
bool isShowAnimationRunning() const
void animatedShow()
int heightForWidth(int width) const override
void setMessageType(KMessageWidget::MessageType type)
void setText(const QString &text)
Q_SCRIPTABLE CaptureState status()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void initIcons()
KIOCORE_EXPORT CopyJob * copy(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
QString name(const QVariant &location)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KGuiItem cont()
KGuiItem cancel()
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
QFont font()
void setText(const QString &text, Mode mode)
QString toString(QStringView format, QCalendar cal) const const
QClipboard * clipboard()
typedef ConstIterator
void append(QList< T > &&value)
void clear()
const_iterator constBegin() const const
const_iterator constEnd() const const
T & first()
bool isEmpty() const const
Qt::ItemFlags flags() const const
void setFlags(Qt::ItemFlags flags)
void setText(const QString &text)
const_iterator constBegin() const const
const_iterator constEnd() const const
bool contains(const Key &key) const const
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QObject * parent() const const
int width() const const
QString arg(Args &&... args) const const
QChar * data()
bool isEmpty() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QString join(QChar separator) const const
DisplayRole
ItemIsEditable
MatchExactly
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
Qt::ItemFlags flags() const const
void setFlags(Qt::ItemFlags flags)
void setText(int column, const QString &text)
QWidget(QWidget *parent, Qt::WindowFlags f)
void hide()
QLayout * layout() const const
void setLayout(QLayout *layout)
void setTabOrder(QWidget *first, QWidget *second)
void show()
void resize(const QSize &)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Mar 7 2025 11:47:44 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.