diff --git a/choqok/config/accounts/accountswidget.cpp b/choqok/config/accounts/accountswidget.cpp index 5b375956..2111358d 100644 --- a/choqok/config/accounts/accountswidget.cpp +++ b/choqok/config/accounts/accountswidget.cpp @@ -1,350 +1,350 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "accountswidget.h" #include #include #include #include #include #include #include #include "accountmanager.h" #include "accountsdebug.h" #include "addaccountdialog.h" #include "choqokuiglobal.h" #include "editaccountwidget.h" #include "editaccountdialog.h" #include "microblog.h" #include "pluginmanager.h" K_PLUGIN_FACTORY_WITH_JSON(ChoqokAccountsConfigFactory, "choqok_accountsconfig.json", registerPlugin();) AccountsWidget::AccountsWidget(QWidget *parent, const QVariantList &args) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_accountsconfig")) , parent, args) { qCDebug(CHOQOK); setAttribute(Qt::WA_DeleteOnClose); setupUi(this); connect(accountsTable, &QTableWidget::cellDoubleClicked,this, &AccountsWidget::accountsTableCellDoubleClicked); connect(accountsTable, &QTableWidget::cellClicked, this, &AccountsWidget::accountsTableCellClicked); accountsTable->horizontalHeader()->setStretchLastSection(true); connect(btnUp, &QPushButton::clicked, this, &AccountsWidget::moveCurrentRowUp); connect(btnDown, &QPushButton::clicked, this, &AccountsWidget::moveCurrentRowDown); connect(btnEdit, SIGNAL(clicked()), this, SLOT(editAccount())); connect(btnRemove, SIGNAL(clicked()), this, SLOT(removeAccount())); connect(accountsTable, &QTableWidget::currentItemChanged, this, &AccountsWidget::accountsTablestateChanged); connect(Choqok::AccountManager::self(), &Choqok::AccountManager::accountAdded, this, &AccountsWidget::slotAccountAdded); connect(Choqok::AccountManager::self(), &Choqok::AccountManager::accountRemoved, this, &AccountsWidget::slotAccountRemoved); btnAdd->setMenu(createAddAccountMenu()); // load(); } AccountsWidget::~AccountsWidget() { qCDebug(CHOQOK); } void AccountsWidget::addAccount() { qCDebug(CHOQOK); QAction *act = qobject_cast(sender()); if (act) { QString name = act->data().toString(); Choqok::MicroBlog *blog = qobject_cast(Choqok::PluginManager::self()->loadPlugin(name)); if (blog) { QPointer d = new AddAccountDialog( blog->createEditAccountWidget(0, Choqok::UI::Global::mainWindow()), Choqok::UI::Global::mainWindow()); d->setModal(true); d->exec(); } else { KMessageBox::sorry(this, i18n("Cannot load the %1 plugin. Please check your installation.", name)); } } } void AccountsWidget::editAccount(QString alias) { qCDebug(CHOQOK); int currentRow = accountsTable->currentRow(); if (alias.isEmpty()) { alias = accountsTable->item(currentRow, 0)->text(); } QPointer currentAccount = Choqok::AccountManager::self()->findAccount(alias); if (!currentAccount) { KMessageBox::detailedSorry(this, i18n("Cannot find the desired account."), Choqok::AccountManager::self()->lastError()); return; } else { ChoqokEditAccountWidget *eaw = currentAccount->microblog()->createEditAccountWidget(currentAccount, this); QPointer d = new EditAccountDialog(eaw, this); d->setModal(true); d->exec(); emitChanged(); // Needs for update alias after editing account accountsTable->setItem(currentRow, 0, new QTableWidgetItem(currentAccount->alias())); } } void AccountsWidget::removeAccount(QString alias) { qCDebug(CHOQOK) << alias; if (KMessageBox::warningYesNoCancel(this, i18n("Are you sure you want to remove the selected account?")) == KMessageBox::Yes) { if (alias.isEmpty()) { alias = accountsTable->item(accountsTable->currentRow(), 0)->text(); } if (!Choqok::AccountManager::self()->removeAccount(alias)) { KMessageBox::detailedSorry(this, i18n("Cannot remove the account."), Choqok::AccountManager::self()->lastError()); } } } void AccountsWidget::slotAccountAdded(Choqok::Account *account) { qCDebug(CHOQOK); addAccountToTable(account); emitChanged(); } void AccountsWidget::slotAccountRemoved(const QString alias) { qCDebug(CHOQOK); int count = accountsTable->rowCount(); for (int i = 0; i < count; ++i) { if (accountsTable->item(i, 0)->text() == alias) { accountsTable->removeRow(i); emitChanged(); break; } } } void AccountsWidget::addAccountToTable(Choqok::Account *account) { qCDebug(CHOQOK); int row = accountsTable->rowCount(); accountsTable->setRowCount(row + 1); // accountsTable->insertRow(row); // QCheckBox *enable = new QCheckBox ( accountsTable ); // enable->setChecked ( account->isEnabled() ); // accountsTable->setCellWidget ( row, 0, enable ); accountsTable->setItem(row, 0, new QTableWidgetItem(account->alias())); accountsTable->setItem(row, 1, new QTableWidgetItem(QIcon::fromTheme(account->microblog()->pluginIcon()), account->microblog()->serviceName())); QCheckBox *enabled = new QCheckBox(accountsTable); enabled->setChecked(account->isEnabled()); accountsTable->setCellWidget(row, 2, enabled); QCheckBox *readOnly = new QCheckBox(accountsTable); readOnly->setChecked(account->isReadOnly()); accountsTable->setCellWidget(row, 3, readOnly); QCheckBox *quick = new QCheckBox(accountsTable); quick->setChecked(account->showInQuickPost()); accountsTable->setCellWidget(row, 4, quick); connect(enabled, &QCheckBox::toggled, this, &AccountsWidget::emitChanged); connect(readOnly, &QCheckBox::toggled, this, &AccountsWidget::emitChanged); - connect(quick, &QCheckBox::toggled, this, &AccountsWidget::emitChanged); + connect(quick, &QCheckBox::toggled, this, &AccountsWidget::emitChanged); } void AccountsWidget::accountsTablestateChanged() { qCDebug(CHOQOK); int current = accountsTable->currentRow(); qCDebug(CHOQOK) << current; if (current >= 0 && accountsTable->selectedItems().count() > 0) { btnEdit->setEnabled(true); btnRemove->setEnabled(true); btnUp->setEnabled(current != 0); btnDown->setEnabled(current != accountsTable->rowCount() - 1); } else { btnEdit->setEnabled(false); btnRemove->setEnabled(false); btnUp->setEnabled(false); btnDown->setEnabled(false); } } void AccountsWidget::load() { qCDebug(CHOQOK); accountsTable->clearContents(); accountsTable->setRowCount(0); for (Choqok::Account *ac: Choqok::AccountManager::self()->accounts()) { addAccountToTable(ac); } accountsTable->resizeColumnsToContents(); } void AccountsWidget::save() { qCDebug(CHOQOK); const int rowCount = accountsTable->rowCount(); bool changed; for (int i = 0; i < rowCount; ++i) { changed = false; Choqok::Account *acc = Choqok::AccountManager::self()->findAccount(accountsTable->item(i, 0)->text()); if (!acc) { continue; } if (acc->priority() != (uint)i) { acc->setPriority((uint)i); changed = true; } QCheckBox *enabled = qobject_cast(accountsTable->cellWidget(i, 2)); if (enabled && acc->isEnabled() != enabled->isChecked()) { acc->setEnabled(enabled->isChecked()); changed = true; } QCheckBox *readOnly = qobject_cast(accountsTable->cellWidget(i, 3)); if (readOnly && acc->isReadOnly() != readOnly->isChecked()) { acc->setReadOnly(readOnly->isChecked()); changed = true; } QCheckBox *showOnQuick = qobject_cast(accountsTable->cellWidget(i, 4)); if (showOnQuick && acc->showInQuickPost() != showOnQuick->isChecked()) { acc->setShowInQuickPost(showOnQuick->isChecked()); changed = true; } if (changed) { //Maybe we should call writeConfig() from setShowInQuickPost(), setReadOnly() and setPriority() -Mehrdad acc->writeConfig(); } } } QMenu *AccountsWidget::createAddAccountMenu() { mBlogMenu = new QMenu(i18n("Select Micro-Blogging Service"), this); const QList list = Choqok::PluginManager::self()->availablePlugins(QLatin1String("MicroBlogs")); for (const KPluginInfo &info: list) { QAction *act = new QAction(mBlogMenu); act->setText(info.name()); act->setIcon(QIcon::fromTheme(info.icon())); act->setData(info.pluginName()); connect(act, &QAction::triggered, this, &AccountsWidget::addAccount); mBlogMenu->addAction(act); } return mBlogMenu; } void AccountsWidget::moveCurrentRowUp() { move(true); } void AccountsWidget::moveCurrentRowDown() { move(false); } void AccountsWidget::move(bool up) { if (accountsTable->selectedItems().count() <= 0) { return; } emitChanged(); const int sourceRow = accountsTable->row(accountsTable->selectedItems().at(0)); bool sourceEnabled = qobject_cast(accountsTable->cellWidget(sourceRow, 2))->isChecked(); bool sourceReadOnly = qobject_cast(accountsTable->cellWidget(sourceRow, 3))->isChecked(); bool sourceQuickPost = qobject_cast(accountsTable->cellWidget(sourceRow, 4))->isChecked(); const int destRow = (up ? sourceRow - 1 : sourceRow + 1); if (destRow < 0 || (destRow >= accountsTable->rowCount())) { return; } bool destEnabled = qobject_cast(accountsTable->cellWidget(destRow, 2))->isChecked(); bool destReadOnly = qobject_cast(accountsTable->cellWidget(destRow, 3))->isChecked(); bool destQuickPost = qobject_cast(accountsTable->cellWidget(destRow, 4))->isChecked(); // take whole rows QList sourceItems = takeRow(sourceRow); QList destItems = takeRow(destRow); // set back in reverse order setRow(sourceRow, destItems); setRow(destRow, sourceItems); // taking whole row doesn't work! so changing value of checkBoxes take place here. qobject_cast(accountsTable->cellWidget(sourceRow, 2))->setChecked(destEnabled); qobject_cast(accountsTable->cellWidget(sourceRow, 3))->setChecked(destReadOnly); qobject_cast(accountsTable->cellWidget(sourceRow, 4))->setChecked(destQuickPost); qobject_cast(accountsTable->cellWidget(destRow, 2))->setChecked(sourceEnabled); qobject_cast(accountsTable->cellWidget(destRow, 3))->setChecked(sourceReadOnly); qobject_cast(accountsTable->cellWidget(destRow, 4))->setChecked(sourceQuickPost); accountsTable->setCurrentCell(destRow, 0); KMessageBox::information(this, i18n("You need to restart Choqok for the accounts priority changes to take effect."), QString(), QLatin1String("ChangeAccountsPriority")); } // takes and returns the whole row QList AccountsWidget::takeRow(int row) { QList rowItems; for (int col = 0; col < accountsTable->columnCount(); ++col) { rowItems << accountsTable->takeItem(row, col); } return rowItems; } // sets the whole row void AccountsWidget::setRow(int row, const QList &rowItems) { for (int col = 0; col < accountsTable->columnCount(); ++col) { accountsTable->setItem(row, col, rowItems.at(col)); } } void AccountsWidget::emitChanged() { Q_EMIT changed(true); } void AccountsWidget::accountsTableCellDoubleClicked(int row, int column) { Q_UNUSED(row); Q_UNUSED(column); editAccount(); } void AccountsWidget::accountsTableCellClicked(int row, int column) { Q_UNUSED(column); accountsTable->selectRow(row); accountsTablestateChanged(); } #include "accountswidget.moc" diff --git a/choqok/config/behavior/behaviorconfig.cpp b/choqok/config/behavior/behaviorconfig.cpp index 39bd7e8f..a25b0196 100644 --- a/choqok/config/behavior/behaviorconfig.cpp +++ b/choqok/config/behavior/behaviorconfig.cpp @@ -1,128 +1,130 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "behaviorconfig.h" #include "ui_behaviorconfig_general.h" #include "ui_behaviorconfig_notifications.h" #include #include #include #include #include #include #include #include "behaviorconfig_shorten.h" #include "behaviordebug.h" #include "choqokbehaviorsettings.h" K_PLUGIN_FACTORY_WITH_JSON(ChoqokBehaviorConfigFactory, "choqok_behaviorconfig.json", registerPlugin();) class BehaviorConfig::Private { public: QTabWidget *mBehaviorTabCtl; Ui_BehaviorConfig_General mPrfsGeneral; Ui_BehaviorConfig_Notifications mPrfsNotify; BehaviorConfig_Shorten *mPrfsShorten; KCModuleProxy *proxyModule; }; BehaviorConfig::BehaviorConfig(QWidget *parent, const QVariantList &args) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_behaviorconfig")), parent, args) , d(new Private) { qCDebug(CHOQOK); QVBoxLayout *layout = new QVBoxLayout(this); // since KSetting::Dialog has margins here, we don't need our own. layout->setContentsMargins(0, 0, 0, 0); d->mBehaviorTabCtl = new QTabWidget(this); d->mBehaviorTabCtl->setObjectName(QLatin1String("mBehaviorTabCtl")); layout->addWidget(d->mBehaviorTabCtl); // "General" TAB ============================================================ QWidget *mPrfsGeneralDlg = new QWidget(d->mBehaviorTabCtl); d->mPrfsGeneral.setupUi(mPrfsGeneralDlg); addConfig(Choqok::BehaviorSettings::self(), mPrfsGeneralDlg); d->mBehaviorTabCtl->addTab(mPrfsGeneralDlg, i18n("&General")); #ifdef QTINDICATE_BUILD // "Notifications" TAB ============================================================ QWidget *mPrfsNotifyDlg = new QWidget(d->mBehaviorTabCtl); d->mPrfsNotify.setupUi(mPrfsNotifyDlg); addConfig(Choqok::BehaviorSettings::self(), mPrfsNotifyDlg); d->mBehaviorTabCtl->addTab(mPrfsNotifyDlg, i18n("&Notifications")); /* Remove below code, when all functions on tab will work*/ d->mPrfsNotify.kcfg_notifyInterval->setVisible(false); d->mPrfsNotify.kcfg_showAllNotifiesInOne->setVisible(false); d->mPrfsNotify.label_4->setVisible(false); /* */ #endif // "Shortening" TAB =============================================================== d->mPrfsShorten = new BehaviorConfig_Shorten(d->mBehaviorTabCtl); addConfig(Choqok::BehaviorSettings::self(), d->mPrfsShorten); d->mBehaviorTabCtl->addTab(d->mPrfsShorten, i18n("URL &Shortening")); KCModuleInfo proxyInfo(QLatin1String("proxy.desktop")); d->proxyModule = new KCModuleProxy(proxyInfo, parent); d->mBehaviorTabCtl->addTab(d->proxyModule, proxyInfo.moduleName()); - connect(d->mPrfsShorten, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); - connect(d->proxyModule, SIGNAL(changed(bool)), this, SIGNAL(changed(bool))); + connect(d->mPrfsShorten, (void (BehaviorConfig_Shorten::*)(bool))&BehaviorConfig_Shorten::changed, + this, (void (KCModule::*)())&KCModule::changed); + connect(d->proxyModule, (void (KCModuleProxy::*)(KCModuleProxy*))&KCModuleProxy::changed, + this, (void (KCModule::*)())&KCModule::changed); load(); } BehaviorConfig::~BehaviorConfig() { delete d; } void BehaviorConfig::save() { qCDebug(CHOQOK); KCModule::save(); d->mPrfsShorten->save(); d->proxyModule->save(); // Choqok::BehaviorSettings::self()->writeConfig(); load(); } void BehaviorConfig::load() { KCModule::load(); d->mPrfsShorten->load(); d->proxyModule->load(); } #include "behaviorconfig.moc" diff --git a/choqok/config/behavior/behaviorconfig_shorten.cpp b/choqok/config/behavior/behaviorconfig_shorten.cpp index 12f06214..01d697e7 100644 --- a/choqok/config/behavior/behaviorconfig_shorten.cpp +++ b/choqok/config/behavior/behaviorconfig_shorten.cpp @@ -1,214 +1,216 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "behaviorconfig_shorten.h" +#include #include #include #include #include #include #include #include #include #include #include "choqokbehaviorsettings.h" #include "behaviordebug.h" #include "pluginmanager.h" #include "shortenmanager.h" BehaviorConfig_Shorten::BehaviorConfig_Shorten(QWidget *parent) : QWidget(parent), currentShortener(0) { qCDebug(CHOQOK); setupUi(this); Choqok::ShortenManager::self(); - connect(shortenPlugins, SIGNAL(currentIndexChanged(int)), SLOT(currentPluginChanged(int))); + connect(shortenPlugins, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &BehaviorConfig_Shorten::currentPluginChanged); connect(aboutPlugin, &QPushButton::clicked, this, &BehaviorConfig_Shorten::slotAboutClicked); connect(configPlugin, &QPushButton::clicked, this, &BehaviorConfig_Shorten::slotConfigureClicked); } BehaviorConfig_Shorten::~BehaviorConfig_Shorten() { qCDebug(CHOQOK); } void BehaviorConfig_Shorten::currentPluginChanged(int index) { if (shortenPlugins->itemData(index).toString() == prevShortener) { Q_EMIT changed(false); } else { Q_EMIT changed(true); } QString key = shortenPlugins->itemData(index).toString(); // qCDebug(CHOQOK)< 0) { configPlugin->setEnabled(true); } else { configPlugin->setEnabled(false); } // if(currentShortener){ // layout()->removeWidget(currentShortener->configWidget()); // // currentShortener->deleteLater(); // // currentShortener = 0; // } // currentShortener = qobject_cast(Choqok::PluginManager::self()->loadPlugin( // kcfg_plugins->itemData(index).toString() ) ); // if(currentShortener && currentShortener->configWidget()) // layout()->addWidget(currentShortener->configWidget()); } void BehaviorConfig_Shorten::load() { QList plugins = Choqok::PluginManager::self()->availablePlugins(QLatin1String("Shorteners")); shortenPlugins->clear(); shortenPlugins->addItem(i18nc("No shortener service", "None"), QLatin1String("none")); for (const KPluginInfo &plugin: plugins) { shortenPlugins->addItem(QIcon::fromTheme(plugin.icon()), plugin.name(), plugin.pluginName()); availablePlugins.insert(plugin.pluginName(), plugin); } prevShortener = Choqok::BehaviorSettings::shortenerPlugin(); if (!prevShortener.isEmpty()) { shortenPlugins->setCurrentIndex(shortenPlugins->findData(prevShortener)); // currentPluginChanged(kcfg_plugins->currentIndex()); } } void BehaviorConfig_Shorten::save() { const QString shorten = shortenPlugins->itemData(shortenPlugins->currentIndex()).toString(); Choqok::BehaviorSettings::setShortenerPlugin(shorten); if (prevShortener != shorten) { qCDebug(CHOQOK) << prevShortener << "->" << shorten; Choqok::BehaviorSettings::self()->save(); Choqok::ShortenManager::self()->reloadConfig(); } } void BehaviorConfig_Shorten::slotAboutClicked() { const QString shorten = shortenPlugins->itemData(shortenPlugins->currentIndex()).toString(); if (shorten == QLatin1String("none")) { return; } KPluginInfo info = availablePlugins.value(shorten); KAboutData aboutData(info.name(), info.name(), info.version(), info.comment(), KAboutLicense::byKeyword(info.license()).key(), QString(), QString(), info.website()); aboutData.addAuthor(info.author(), QString(), info.email()); KAboutApplicationDialog aboutPlugin(aboutData, this); aboutPlugin.setWindowIcon(QIcon::fromTheme(info.icon())); aboutPlugin.exec(); } void BehaviorConfig_Shorten::slotConfigureClicked() { qCDebug(CHOQOK); KPluginInfo pluginInfo = availablePlugins.value(shortenPlugins->itemData(shortenPlugins->currentIndex()).toString()); qCDebug(CHOQOK) << pluginInfo.name() << pluginInfo.kcmServices().count(); QPointer configDialog = new QDialog(this); configDialog->setWindowTitle(pluginInfo.name()); // The number of KCModuleProxies in use determines whether to use a tabwidget QTabWidget *newTabWidget = 0; // Widget to use for the setting dialog's main widget, // either a QTabWidget or a KCModuleProxy QWidget *mainWidget = 0; // Widget to use as the KCModuleProxy's parent. // The first proxy is owned by the dialog itself QWidget *moduleProxyParentWidget = configDialog; for (const KService::Ptr &servicePtr: pluginInfo.kcmServices()) { if (!servicePtr->noDisplay()) { KCModuleInfo moduleInfo(servicePtr); KCModuleProxy *currentModuleProxy = new KCModuleProxy(moduleInfo, moduleProxyParentWidget); if (currentModuleProxy->realModule()) { moduleProxyList << currentModuleProxy; if (mainWidget && !newTabWidget) { // we already created one KCModuleProxy, so we need a tab widget. // Move the first proxy into the tab widget and ensure this and subsequent // proxies are in the tab widget newTabWidget = new QTabWidget(configDialog); moduleProxyParentWidget = newTabWidget; mainWidget->setParent(newTabWidget); KCModuleProxy *moduleProxy = qobject_cast(mainWidget); if (moduleProxy) { newTabWidget->addTab(mainWidget, moduleProxy->moduleInfo().moduleName()); mainWidget = newTabWidget; } else { delete newTabWidget; newTabWidget = 0; moduleProxyParentWidget = configDialog; mainWidget->setParent(0); } } if (newTabWidget) { newTabWidget->addTab(currentModuleProxy, servicePtr->name()); } else { mainWidget = currentModuleProxy; } } else { delete currentModuleProxy; } } } // it could happen that we had services to show, but none of them were real modules. if (moduleProxyList.count()) { QWidget *showWidget = new QWidget(configDialog); QVBoxLayout *layout = new QVBoxLayout; showWidget->setLayout(layout); layout->addWidget(mainWidget); layout->insertSpacing(-1, QApplication::style()->pixelMetric(QStyle::PM_DialogButtonsSeparator)); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, &QDialogButtonBox::accepted, configDialog.data(), &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, configDialog.data(), &QDialog::reject); layout->addWidget(buttonBox); showWidget->adjustSize(); // connect(&configDialog, SIGNAL(defaultClicked()), this, SLOT(slotDefaultClicked())); if (configDialog->exec() == QDialog::Accepted) { for (KCModuleProxy *moduleProxy: moduleProxyList) { QStringList parentComponents = moduleProxy->moduleInfo().service()->property(QLatin1String("X-KDE-ParentComponents")).toStringList(); moduleProxy->save(); } } else { for (KCModuleProxy *moduleProxy: moduleProxyList) { moduleProxy->load(); } } qDeleteAll(moduleProxyList); moduleProxyList.clear(); } } diff --git a/choqok/config/plugins/choqokpluginconfig.cpp b/choqok/config/plugins/choqokpluginconfig.cpp index 9d1eade9..1a5f4fc2 100644 --- a/choqok/config/plugins/choqokpluginconfig.cpp +++ b/choqok/config/plugins/choqokpluginconfig.cpp @@ -1,90 +1,91 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "choqokpluginconfig.h" #include #include #include #include #include #include #include "pluginmanager.h" #include "pluginsdebug.h" K_PLUGIN_FACTORY_WITH_JSON(ChoqokPluginConfigFactory, "choqok_pluginconfig.json", registerPlugin();) ChoqokPluginConfig::ChoqokPluginConfig(QWidget *parent, const QVariantList &args) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_pluginconfig")), parent, args) { m_pluginSelector = new KPluginSelector(this); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); mainLayout->addWidget(m_pluginSelector); - connect(m_pluginSelector, SIGNAL(changed(bool)), this, SLOT(changed())); + connect(m_pluginSelector, &KPluginSelector::changed, this, + (void (KCModule::*)())&KCModule::changed); connect(m_pluginSelector, &KPluginSelector::configCommitted, this, &ChoqokPluginConfig::reparseConfiguration); m_pluginSelector->addPlugins(Choqok::PluginManager::self()->availablePlugins(QLatin1String("Plugins")), KPluginSelector::ReadConfigFile, i18n("General Plugins"), QLatin1String("Plugins")); // m_pluginSelector->addPlugins( Choqok::PluginManager::self()->availablePlugins( "Shorteners" ), // KPluginSelector::ReadConfigFile, i18n("Shortener Plugins"), "Shorteners"); m_pluginSelector->load(); } ChoqokPluginConfig::~ChoqokPluginConfig() { } void ChoqokPluginConfig::reparseConfiguration(const QByteArray &conf) { KSettings::Dispatcher::reparseConfiguration(QLatin1String(conf)); } void ChoqokPluginConfig::load() { m_pluginSelector->load(); KCModule::load(); } void ChoqokPluginConfig::defaults() { m_pluginSelector->defaults(); } void ChoqokPluginConfig::save() { m_pluginSelector->save(); Choqok::PluginManager::self()->loadAllPlugins(); KCModule::save(); } #include "choqokpluginconfig.moc" diff --git a/helperlibs/gnusocialapihelper/gnusocialapicomposerwidget.cpp b/helperlibs/gnusocialapihelper/gnusocialapicomposerwidget.cpp index 3d02a5cb..92318f96 100644 --- a/helperlibs/gnusocialapihelper/gnusocialapicomposerwidget.cpp +++ b/helperlibs/gnusocialapihelper/gnusocialapicomposerwidget.cpp @@ -1,175 +1,171 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "gnusocialapicomposerwidget.h" #include #include #include #include #include #include #include "account.h" #include "choqoktextedit.h" #include "microblog.h" #include "notifymanager.h" #include "shortenmanager.h" #include "twitterapitextedit.h" #include "gnusocialapidebug.h" #include "gnusocialapimicroblog.h" class GNUSocialApiComposerWidget::Private { public: Private() : btnAttach(0), mediumName(0), btnCancel(0) {} QString mediumToAttach; QPushButton *btnAttach; QPointer mediumName; QPointer btnCancel; QGridLayout *editorLayout; }; GNUSocialApiComposerWidget::GNUSocialApiComposerWidget(Choqok::Account *account, QWidget *parent) : TwitterApiComposerWidget(account, parent), d(new Private) { d->editorLayout = qobject_cast(editorContainer()->layout()); d->btnAttach = new QPushButton(editorContainer()); d->btnAttach->setIcon(QIcon::fromTheme(QLatin1String("mail-attachment"))); d->btnAttach->setToolTip(i18n("Attach a file")); d->btnAttach->setMaximumWidth(d->btnAttach->height()); - connect(d->btnAttach, SIGNAL(clicked(bool)), this, SLOT(selectMediumToAttach())); + connect(d->btnAttach, &QPushButton::clicked, this, &GNUSocialApiComposerWidget::selectMediumToAttach); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(d->btnAttach); vLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding)); d->editorLayout->addItem(vLayout, 0, 1, 1, 1); - connect(account, SIGNAL(modified(Choqok::Account*)), this, SLOT(slotRebuildEditor(Choqok::Account*))); + connect(account, &Choqok::Account::modified, this, &GNUSocialApiComposerWidget::slotRebuildEditor); } GNUSocialApiComposerWidget::~GNUSocialApiComposerWidget() { delete d; } void GNUSocialApiComposerWidget::submitPost(const QString &txt) { if (d->mediumToAttach.isEmpty()) { Choqok::UI::ComposerWidget::submitPost(txt); } else { qCDebug(CHOQOK); editorContainer()->setEnabled(false); QString text = txt; if (currentAccount()->postCharLimit() && text.size() > (int)currentAccount()->postCharLimit()) { text = Choqok::ShortenManager::self()->parseText(text); } setPostToSubmit(nullptr); setPostToSubmit(new Choqok::Post); postToSubmit()->content = text; if (!replyToId.isEmpty()) { postToSubmit()->replyToPostId = replyToId; } - connect(currentAccount()->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - SLOT(slotPostMediaSubmitted(Choqok::Account*,Choqok::Post*))); - connect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, + this, &GNUSocialApiComposerWidget::slotPostMediaSubmitted); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, + this, &GNUSocialApiComposerWidget::slotErrorPost); btnAbort = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("Abort"), this); layout()->addWidget(btnAbort); - connect(btnAbort, SIGNAL(clicked(bool)), SLOT(abort())); + connect(btnAbort, &QPushButton::clicked, this, &Choqok::UI::ComposerWidget::abort); GNUSocialApiMicroBlog *mBlog = qobject_cast(currentAccount()->microblog()); mBlog->createPostWithAttachment(currentAccount(), postToSubmit(), d->mediumToAttach); } } void GNUSocialApiComposerWidget::slotPostMediaSubmitted(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (currentAccount() == theAccount && post == postToSubmit()) { qCDebug(CHOQOK) << "Accepted"; - disconnect(currentAccount()->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotPostMediaSubmitted(Choqok::Account*,Choqok::Post*))); - disconnect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, + this, &GNUSocialApiComposerWidget::slotPostMediaSubmitted); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, + this, &GNUSocialApiComposerWidget::slotErrorPost); if (btnAbort) { btnAbort->deleteLater(); } Choqok::NotifyManager::success(i18n("New post submitted successfully")); editor()->clear(); replyToId.clear(); editorContainer()->setEnabled(true); setPostToSubmit(nullptr); cancelAttachMedium(); currentAccount()->microblog()->updateTimelines(currentAccount()); } } void GNUSocialApiComposerWidget::selectMediumToAttach() { qCDebug(CHOQOK); d->mediumToAttach = QFileDialog::getOpenFileName(this, i18n("Select Media to Upload"), QString(), QStringLiteral("Images")); if (d->mediumToAttach.isEmpty()) { return; } QString fileName = QUrl(d->mediumToAttach).fileName(); if (!d->mediumName) { qCDebug(CHOQOK) << fileName; d->mediumName = new QLabel(editorContainer()); d->btnCancel = new QPushButton(editorContainer()); d->btnCancel->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->btnCancel->setToolTip(i18n("Discard Attachment")); d->btnCancel->setMaximumWidth(d->btnCancel->height()); - connect(d->btnCancel, SIGNAL(clicked(bool)), SLOT(cancelAttachMedium())); + connect(d->btnCancel, &QPushButton::clicked, this, &GNUSocialApiComposerWidget::cancelAttachMedium); d->editorLayout->addWidget(d->mediumName, 1, 0); d->editorLayout->addWidget(d->btnCancel, 1, 1); } d->mediumName->setText(i18n("Attaching %1", fileName)); editor()->setFocus(); } void GNUSocialApiComposerWidget::cancelAttachMedium() { qCDebug(CHOQOK); delete d->mediumName; d->mediumName = 0; delete d->btnCancel; d->btnCancel = 0; d->mediumToAttach.clear(); } void GNUSocialApiComposerWidget::slotRebuildEditor(Choqok::Account *theAccount) { setEditor(new TwitterApiTextEdit(theAccount, this)); } diff --git a/helperlibs/gnusocialapihelper/gnusocialapiconversationtimelinewidget.cpp b/helperlibs/gnusocialapihelper/gnusocialapiconversationtimelinewidget.cpp index 5f05899e..ea9d904d 100644 --- a/helperlibs/gnusocialapihelper/gnusocialapiconversationtimelinewidget.cpp +++ b/helperlibs/gnusocialapihelper/gnusocialapiconversationtimelinewidget.cpp @@ -1,89 +1,89 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2011-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "gnusocialapiconversationtimelinewidget.h" #include #include #include "choqokappearancesettings.h" #include "postwidget.h" #include "gnusocialapimicroblog.h" GNUSocialApiConversationTimelineWidget::GNUSocialApiConversationTimelineWidget(Choqok::Account *curAccount, const QString &convId, QWidget *parent) : TwitterApiTimelineWidget(curAccount, i18n("Conversation %1", convId), parent) { setWindowTitle(i18n("Please wait...")); GNUSocialApiMicroBlog *mBlog = qobject_cast(curAccount->microblog()); resize(choqokMainWindow->width(), 500); move(choqokMainWindow->pos()); conversationId = convId; - connect(mBlog, SIGNAL(conversationFetched(Choqok::Account*,QString,QList)), - this, SLOT(slotConversationFetched(Choqok::Account*,QString,QList))); + connect(mBlog, &GNUSocialApiMicroBlog::conversationFetched, + this, &GNUSocialApiConversationTimelineWidget::slotConversationFetched); mBlog->fetchConversation(curAccount, convId); } GNUSocialApiConversationTimelineWidget::~GNUSocialApiConversationTimelineWidget() { } void GNUSocialApiConversationTimelineWidget::saveTimeline() { } void GNUSocialApiConversationTimelineWidget::loadTimeline() { } void GNUSocialApiConversationTimelineWidget::slotConversationFetched(Choqok::Account *theAccount, const QString &convId, QList< Choqok::Post * > posts) { if (currentAccount() == theAccount && convId == this->conversationId) { setWindowTitle(i18n("Conversation")); addNewPosts(posts); for (Choqok::UI::PostWidget *post: postWidgets()) { post->setReadWithSignal(); } QTimer::singleShot(0, this, SLOT(updateHeight())); } } void GNUSocialApiConversationTimelineWidget::updateHeight() { int height = 25; for (Choqok::UI::PostWidget *wd: postWidgets()) { height += wd->height() + 5; } if (height > choqokMainWindow->height()) { height = choqokMainWindow->height(); } resize(width(), height); if (!Choqok::AppearanceSettings::useReverseOrder()) { scrollToBottom(); } } diff --git a/helperlibs/gnusocialapihelper/gnusocialapimicroblog.cpp b/helperlibs/gnusocialapihelper/gnusocialapimicroblog.cpp index 8544b423..98bab7e2 100644 --- a/helperlibs/gnusocialapihelper/gnusocialapimicroblog.cpp +++ b/helperlibs/gnusocialapihelper/gnusocialapimicroblog.cpp @@ -1,422 +1,421 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "gnusocialapimicroblog.h" #include #include #include #include #include #include #include #include #include "account.h" #include "accountmanager.h" #include "choqokappearancesettings.h" #include "composerwidget.h" #include "editaccountwidget.h" #include "mediamanager.h" #include "microblogwidget.h" #include "postwidget.h" #include "timelinewidget.h" #include "twitterapimicroblogwidget.h" #include "twitterapipostwidget.h" #include "twitterapitimelinewidget.h" #include "gnusocialapiaccount.h" #include "gnusocialapicomposerwidget.h" #include "gnusocialapidebug.h" #include "gnusocialapidmessagedialog.h" #include "gnusocialapipostwidget.h" #include "gnusocialapisearch.h" GNUSocialApiMicroBlog::GNUSocialApiMicroBlog(const QString &componentName, QObject *parent = 0) : TwitterApiMicroBlog(componentName, parent), friendsPage(1) { qCDebug(CHOQOK); setServiceName(QLatin1String("GNU social")); mTimelineInfos[QLatin1String("ReTweets")]->name = i18nc("Timeline name", "Repeated"); mTimelineInfos[QLatin1String("ReTweets")]->description = i18nc("Timeline description", "Your posts that were repeated by others"); } GNUSocialApiMicroBlog::~GNUSocialApiMicroBlog() { qCDebug(CHOQOK); } Choqok::Account *GNUSocialApiMicroBlog::createNewAccount(const QString &alias) { GNUSocialApiAccount *acc = qobject_cast(Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return new GNUSocialApiAccount(this, alias); } else { return 0; } } Choqok::UI::MicroBlogWidget *GNUSocialApiMicroBlog::createMicroBlogWidget(Choqok::Account *account, QWidget *parent) { return new TwitterApiMicroBlogWidget(account, parent); } Choqok::UI::TimelineWidget *GNUSocialApiMicroBlog::createTimelineWidget(Choqok::Account *account, const QString &timelineName, QWidget *parent) { return new TwitterApiTimelineWidget(account, timelineName, parent); } Choqok::UI::PostWidget *GNUSocialApiMicroBlog::createPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) { return new GNUSocialApiPostWidget(account, post, parent); } Choqok::UI::ComposerWidget *GNUSocialApiMicroBlog::createComposerWidget(Choqok::Account *account, QWidget *parent) { return new GNUSocialApiComposerWidget(account, parent); } Choqok::Post *GNUSocialApiMicroBlog::readPost(Choqok::Account *account, const QVariantMap &var, Choqok::Post *post) { if (!post) { qCCritical(CHOQOK) << "post is NULL!"; return 0; } if (var[QLatin1String("source")].toString().compare(QLatin1String("linkback")) == 0) { // Skip linkback statuses return 0; } post = TwitterApiMicroBlog::readPost(account, var, post); QUrl profileUrl = var[QLatin1String("user")].toMap()[QLatin1String("statusnet_profile_url")].toUrl(); post->author.homePageUrl = profileUrl; const QVariantMap retweeted = var[QLatin1String("retweeted_status")].toMap(); if (!retweeted.isEmpty()) { profileUrl = retweeted[QLatin1String("user")].toMap()[QLatin1String("statusnet_profile_url")].toUrl(); post->repeatedFromUser.homePageUrl = profileUrl; } if (var.contains(QLatin1String("uri"))) { post->link = var[QLatin1String("uri")].toUrl(); } else if (var.contains(QLatin1String("external_url"))) { post->link = var[QLatin1String("external_url")].toUrl(); } else { if (retweeted.contains(QLatin1String("uri"))) { post->link = var[QLatin1String("uri")].toUrl(); } else { // Last try, compone the url. However this only works for GNU Social instances. post->link = QUrl::fromUserInput(QStringLiteral("%1://%2/notice/%3") .arg(profileUrl.scheme()).arg(profileUrl.host()).arg(post->postId)); } } return post; } QUrl GNUSocialApiMicroBlog::profileUrl(Choqok::Account *account, const QString &username) const { if (username.contains(QLatin1Char('@'))) { const QStringList lst = username.split(QLatin1Char('@'), QString::SkipEmptyParts); if (lst.count() == 2) { return QUrl::fromUserInput(QStringLiteral("https://%1/%2").arg(lst[1]).arg(lst[0])); } else { return QUrl(); } } else { GNUSocialApiAccount *acc = qobject_cast(account); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(QLatin1Char('/') + username); return url; } } QUrl GNUSocialApiMicroBlog::postUrl(Choqok::Account *account, const QString &username, const QString &postId) const { Q_UNUSED(username) TwitterApiAccount *acc = qobject_cast(account); if (acc) { QUrl url(acc->homepageUrl()); url.setPath(url.path() + QStringLiteral("/notice/%1").arg(postId)); return url; } else { return QUrl(); } } TwitterApiSearch *GNUSocialApiMicroBlog::searchBackend() { if (!mSearchBackend) { mSearchBackend = new GNUSocialApiSearch(this); } return mSearchBackend; } void GNUSocialApiMicroBlog::createPostWithAttachment(Choqok::Account *theAccount, Choqok::Post *post, const QString &mediumToAttach) { if (mediumToAttach.isEmpty()) { TwitterApiMicroBlog::createPost(theAccount, post); } else { const QUrl picUrl = QUrl::fromUserInput(mediumToAttach); KIO::StoredTransferJob *picJob = KIO::storedGet(picUrl, KIO::Reload, KIO::HideProgressInfo); picJob->exec(); if (picJob->error()) { qCCritical(CHOQOK) << "Job error:" << picJob->errorString(); KMessageBox::detailedError(Choqok::UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file."), picJob->errorString()); return; } const QByteArray picData = picJob->data(); if (picData.count() == 0) { qCCritical(CHOQOK) << "Cannot read the media file, please check if it exists."; KMessageBox::error(Choqok::UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file.")); return; } ///Documentation: http://identi.ca/notice/17779990 TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/statuses/update.json")); const QMimeDatabase db; QByteArray fileContentType = db.mimeTypeForUrl(picUrl).name().toUtf8(); QMap formdata; formdata[QLatin1String("status")] = post->content.toUtf8(); formdata[QLatin1String("in_reply_to_status_id")] = post->replyToPostId.toLatin1(); formdata[QLatin1String("source")] = QCoreApplication::applicationName().toLatin1(); QMap mediafile; mediafile[QLatin1String("name")] = "media"; mediafile[QLatin1String("filename")] = picUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = fileContentType; mediafile[QLatin1String("medium")] = picData; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "Cannot create a http POST request!"; return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: multipart/form-data; boundary=AaB03x")); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mCreatePostMap[ job ] = post; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotCreatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &GNUSocialApiMicroBlog::slotCreatePost); job->start(); } } QString GNUSocialApiMicroBlog::generateRepeatedByUserTooltip(const QString &username) { if (Choqok::AppearanceSettings::showRetweetsInChoqokWay()) { return i18n("Repeat of %1", username); } else { return i18n("Repeated by %1", username); } } QString GNUSocialApiMicroBlog::repeatQuestion() { return i18n("Repeat this notice?"); } void GNUSocialApiMicroBlog::listFriendsUsername(TwitterApiAccount *theAccount, bool active) { Q_UNUSED(active); friendsList.clear(); if (theAccount) { doRequestFriendsScreenName(theAccount, 1); } } QStringList GNUSocialApiMicroBlog::readFriendsScreenName(Choqok::Account *theAccount, const QByteArray &buffer) { QStringList list; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { for (const QJsonValue &u: json.array()) { const QJsonObject user = u.toObject(); if (user.contains(QStringLiteral("statusnet_profile_url"))) { list.append(user.value(QLatin1String("statusnet_profile_url")).toString()); } } } else { QString err = i18n("Retrieving the friends list failed. The data returned from the server is corrupted."); qCDebug(CHOQOK) << "JSON parse error:the buffer is: \n" << buffer; Q_EMIT error(theAccount, ParsingError, err, Critical); } return list; } void GNUSocialApiMicroBlog::requestFriendsScreenName(TwitterApiAccount *theAccount, bool active) { Q_UNUSED(active); doRequestFriendsScreenName(theAccount, 1); } void GNUSocialApiMicroBlog::showDirectMessageDialog(TwitterApiAccount *theAccount, const QString &toUsername) { qCDebug(CHOQOK); if (!theAccount) { QAction *act = qobject_cast(sender()); theAccount = qobject_cast(Choqok::AccountManager::self()->findAccount(act->data().toString())); } GNUSocialApiDMessageDialog *dmsg = new GNUSocialApiDMessageDialog(theAccount, Choqok::UI::Global::mainWindow()); if (!toUsername.isEmpty()) { dmsg->setTo(toUsername); } dmsg->show(); } void GNUSocialApiMicroBlog::doRequestFriendsScreenName(TwitterApiAccount *theAccount, int page) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/statuses/friends.json")); if (page > 1) { QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("page"), QString::number(page)); url.setQuery(urlQuery); } KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRequestFriendsScreenName(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &GNUSocialApiMicroBlog::slotRequestFriendsScreenName); job->start(); } void GNUSocialApiMicroBlog::slotRequestFriendsScreenName(KJob *job) { qCDebug(CHOQOK); TwitterApiAccount *theAccount = qobject_cast(mJobsAccount.take(job)); if (job->error()) { Q_EMIT error(theAccount, ServerError, i18n("Friends list for account %1 could not be updated:\n%2", theAccount->username(), job->errorString()), Normal); return; } KIO::StoredTransferJob *stJob = qobject_cast(job); QStringList newList = readFriendsScreenName(theAccount, stJob->data()); friendsList << newList; if (newList.count() == 100) { doRequestFriendsScreenName(theAccount, ++friendsPage); } else { friendsList.removeDuplicates(); theAccount->setFriendsList(friendsList); Q_EMIT friendsUsernameListed(theAccount, friendsList); } } void GNUSocialApiMicroBlog::fetchConversation(Choqok::Account *theAccount, const QString &conversationId) { qCDebug(CHOQOK); if (conversationId.isEmpty()) { return; } TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(QStringLiteral("/statusnet/conversation/%1.json").arg(conversationId)); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mFetchConversationMap[ job ] = conversationId; mJobsAccount[ job ] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchConversation(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &GNUSocialApiMicroBlog::slotFetchConversation); job->start(); } QString GNUSocialApiMicroBlog::usernameFromProfileUrl(const QString &profileUrl) { // Remove the initial slash from path return QUrl(profileUrl).path().remove(0, 1); } QString GNUSocialApiMicroBlog::hostFromProfileUrl(const QString &profileUrl) { return QUrl(profileUrl).host(); } void GNUSocialApiMicroBlog::slotFetchConversation(KJob *job) { qCDebug(CHOQOK); if (!job) { qCWarning(CHOQOK) << "NULL Job returned"; return; } QList posts; QString conversationId = mFetchConversationMap.take(job); Choqok::Account *theAccount = mJobsAccount.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Fetching conversation failed. %1", job->errorString()), Normal); } else { KIO::StoredTransferJob *stj = qobject_cast (job); //if(format=="json"){ posts = readTimeline(theAccount, stj->data()); //} else { // posts = readTimelineFromXml ( theAccount, stj->data() ); //} if (!posts.isEmpty()) { Q_EMIT conversationFetched(theAccount, conversationId, posts); } } } #include "gnusocialapimicroblog.moc" diff --git a/helperlibs/gnusocialapihelper/gnusocialapipostwidget.cpp b/helperlibs/gnusocialapihelper/gnusocialapipostwidget.cpp index 4124ac00..53446b5b 100644 --- a/helperlibs/gnusocialapihelper/gnusocialapipostwidget.cpp +++ b/helperlibs/gnusocialapihelper/gnusocialapipostwidget.cpp @@ -1,309 +1,309 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "gnusocialapipostwidget.h" #include #include #include #include #include "choqokbehaviorsettings.h" #include "choqoktools.h" #include "notifymanager.h" #include "quickpost.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" #include "twitterapiwhoiswidget.h" #include "gnusocialapiaccount.h" #include "gnusocialapiconversationtimelinewidget.h" #include "gnusocialapidebug.h" #include "gnusocialapimicroblog.h" #include "gnusocialapisearch.h" const QRegExp GNUSocialApiPostWidget::mGroupRegExp(QLatin1String("([\\s]|^)!([a-z0-9]+){1,64}"), Qt::CaseInsensitive); const QRegExp GNUSocialApiPostWidget::mGNUSocialApiUserRegExp(QLatin1String("([\\s\\W]|^)@([a-z0-9_]+){1,64}(?!(@))"), Qt::CaseInsensitive); const QRegExp GNUSocialApiPostWidget::mGNUSocialApiHashRegExp(QLatin1String("([\\s]|^)#([\\w_\\.\\-]+)"), Qt::CaseInsensitive); const QString subdomains = QLatin1String("(([a-z0-9-_]\\.)?)"); const QString dname = QLatin1String("(([a-z0-9-\\x0080-\\xFFFF]){1,63}\\.)+"); const QString zone = QLatin1String("((a[cdefgilmnoqrstuwxz])|(b[abdefghijlmnorstvwyz])|(c[acdfghiklmnoruvxyz])|(d[ejkmoz])|(e[ceghrstu])|\ (f[ijkmor])|(g[abdefghilmnpqrstuwy])|(h[kmnrtu])|(i[delmnoqrst])|(j[emop])|(k[eghimnprwyz])|(l[abcikrstuvy])|\ (m[acdefghklmnopqrstuvwxyz])|(n[acefgilopruz])|(om)|(p[aefghklnrstwy])|(qa)|(r[eosuw])|(s[abcdeghijklmnortuvyz])|\ (t[cdfghjkmnoprtvwz])|(u[agksyz])|(v[aceginu])|(w[fs])|(ye)|(z[amrw])\ |(asia|com|info|net|org|biz|name|pro|aero|cat|coop|edu|jobs|mobi|museum|tel|travel|gov|int|mil|local)|(中国)|(公司)|(网络)|(صر)|(امارات)|(рф))"); const QString domain = QLatin1Char('(') + subdomains + dname + zone + QLatin1Char(')'); const QRegExp GNUSocialApiPostWidget::mStatusNetUserRegExp(QLatin1String("([\\s\\W]|^)@(([a-z0-9]+){1,64}@") + domain + QLatin1Char(')'), Qt::CaseInsensitive); class GNUSocialApiPostWidget::Private { public: Private(Choqok::Account *theAccount) { account = qobject_cast(theAccount); mBlog = qobject_cast(account->microblog()); } GNUSocialApiAccount *account; GNUSocialApiMicroBlog *mBlog; QString tmpUsername; }; GNUSocialApiPostWidget::GNUSocialApiPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) : TwitterApiPostWidget(account, post, parent), d(new Private(account)) { } void GNUSocialApiPostWidget::initUi() { TwitterApiPostWidget::initUi(); QPushButton *btn = buttons().value(QLatin1String("btnResend")); if (btn) { QMenu *menu = new QMenu(btn); QAction *resend = new QAction(i18n("Manual ReSend"), menu); - connect(resend, SIGNAL(triggered(bool)), SLOT(slotResendPost())); + connect(resend, &QAction::triggered, this, &GNUSocialApiPostWidget::slotResendPost); QAction *repeat = new QAction(i18n("Repeat"), menu); repeat->setToolTip(i18n("Repeat post using API")); - connect(repeat, SIGNAL(triggered(bool)), SLOT(repeatPost())); + connect(repeat, &QAction::triggered, this, &GNUSocialApiPostWidget::repeatPost); menu->addAction(repeat); menu->addAction(resend); btn->setMenu(menu); } } GNUSocialApiPostWidget::~GNUSocialApiPostWidget() { delete d; } void GNUSocialApiPostWidget::slotReplyToAll() { QStringList nicks; nicks.append(currentPost()->author.userName); QString txt = QStringLiteral("@%1 ").arg(currentPost()->author.userName); int pos = 0; while ((pos = mGNUSocialApiUserRegExp.indexIn(currentPost()->content, pos)) != -1) { if (mGNUSocialApiUserRegExp.cap(2).toLower() != currentAccount()->username() && mGNUSocialApiUserRegExp.cap(2).toLower() != currentPost()->author.userName && !nicks.contains(mGNUSocialApiUserRegExp.cap(2).toLower())) { nicks.append(mGNUSocialApiUserRegExp.cap(2)); txt += QStringLiteral("@%1 ").arg(mGNUSocialApiUserRegExp.cap(2)); } pos += mGNUSocialApiUserRegExp.matchedLength(); } txt.chop(1); Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName); } QString GNUSocialApiPostWidget::prepareStatus(const QString &text) { QString res = TwitterApiPostWidget::prepareStatus(text); res.replace(mStatusNetUserRegExp, QLatin1String("\\1@\\2")); res.replace(mGNUSocialApiUserRegExp, QLatin1String("\\1@\\2")); res.replace(mGroupRegExp, QLatin1String("\\1!\\2")); res.replace(mGNUSocialApiHashRegExp, QLatin1String("\\1#\\2")); return res; } QString GNUSocialApiPostWidget::generateSign() { return TwitterApiPostWidget::generateSign(); } void GNUSocialApiPostWidget::checkAnchor(const QUrl &url) { QString scheme = url.scheme(); QAction *ret; if (scheme == QLatin1String("tag")) { QString unpcode = QUrl::fromAce(url.host().toUtf8()); unpcode.remove(QLatin1Char('.')); unpcode.remove(QLatin1Char('-')); unpcode.remove(QLatin1Char('_')); QMenu menu; QAction *search = new QAction(QIcon::fromTheme(QLatin1String("system-search")), i18n("Search for %1", unpcode), &menu); QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")), i18n("Open tag page in browser"), &menu); menu.addAction(search); menu.addAction(openInBrowser); menu.setDefaultAction(search); ret = menu.exec(QCursor::pos()); if (ret == search) { d->mBlog->searchBackend()->requestSearchResults(currentAccount(), unpcode, GNUSocialApiSearch::ReferenceHashtag); } else if (ret == openInBrowser) { Choqok::openUrl(QUrl(d->account->homepageUrl().toDisplayString() + QLatin1String("/tag/") + unpcode)); } } else if (scheme == QLatin1String("group")) { QMenu menu; QAction *search = new QAction(QIcon::fromTheme(QLatin1String("system-search")), i18n("Show latest group posts"), &menu); QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")), i18n("Open group page in browser"), &menu); menu.addAction(search); menu.addAction(openInBrowser); menu.setDefaultAction(search); ret = menu.exec(QCursor::pos()); if (ret == search) { d->mBlog->searchBackend()->requestSearchResults(currentAccount(), url.host(), GNUSocialApiSearch::ReferenceGroup); } else if (ret == openInBrowser) { Choqok::openUrl(QUrl(d->account->homepageUrl().toDisplayString() + QLatin1String("/group/") + url.host())); } } else if (scheme == QLatin1String("user")) { QString username = (url.userName().isEmpty() ? QString() : QStringLiteral("%1@").arg(url.userName())) + url.host(); QMenu menu; QAction *info = new QAction(QIcon::fromTheme(QLatin1String("user-identity")), i18nc("Who is user", "Who is %1", username), &menu); QAction *from = new QAction(QIcon::fromTheme(QLatin1String("edit-find-user")), i18nc("Posts from user", "Posts from %1", username), &menu); QAction *to = new QAction(QIcon::fromTheme(QLatin1String("meeting-attending")), i18nc("Replies to user", "Replies to %1", username), &menu); QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")), i18nc("Open profile page in browser", "Open profile in browser"), &menu); menu.addAction(info); if (currentPost()->source != QLatin1String("ostatus")) { menu.addAction(from); menu.addAction(to); from->setData(GNUSocialApiSearch::FromUser); to->setData(GNUSocialApiSearch::ToUser); } menu.addAction(openInBrowser); //Subscribe/UnSubscribe/Block bool isSubscribe = false; QString accountUsername = d->account->username().toLower(); QString postUsername = username.toLower(); QAction *subscribe = 0, *block = 0, *replyTo = 0, *dMessage = 0; if (accountUsername != postUsername) { menu.addSeparator(); QMenu *actionsMenu = menu.addMenu(QIcon::fromTheme(QLatin1String("applications-system")), i18n("Actions")); replyTo = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18nc("Write a message to user attention", "Write to %1", username), actionsMenu); actionsMenu->addAction(replyTo); if (d->account->friendsList().contains(username)) { dMessage = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18nc("Send direct message to user", "Send private message to %1", username), actionsMenu); actionsMenu->addAction(dMessage); isSubscribe = false;//It's UnSubscribe subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-remove-user")), i18nc("Unsubscribe from user", "Unsubscribe from %1", username), actionsMenu); } else { isSubscribe = true; subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), i18nc("Subscribe to user", "Subscribe to %1", username), actionsMenu); } block = new QAction(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18nc("Block user", "Block %1", username), actionsMenu); if (currentPost()->source != QLatin1String("ostatus")) { actionsMenu->addAction(subscribe); actionsMenu->addAction(block); } } ret = menu.exec(QCursor::pos()); if (ret == 0) { return; } if (ret == info) { TwitterApiWhoisWidget *wd = new TwitterApiWhoisWidget(d->account, username, *currentPost(), this); wd->show(QCursor::pos()); return; } else if (ret == subscribe) { if (isSubscribe) { d->mBlog->createFriendship(d->account, username); } else { d->mBlog->destroyFriendship(d->account, username); } return; } else if (ret == block) { d->mBlog->blockUser(d->account, username); return; } else if (ret == openInBrowser) { Choqok::openUrl(currentAccount()->microblog()->profileUrl(currentAccount(), username)); return; } else if (ret == replyTo) { Q_EMIT reply(QStringLiteral("@%1").arg(username), QString(), username); return; } else if (ret == dMessage) { d->mBlog->showDirectMessageDialog(d->account, username); return; } int type = ret->data().toInt(); d->mBlog->searchBackend()->requestSearchResults(currentAccount(), url.host(), type); } else if (scheme == QLatin1String("conversation")) { GNUSocialApiConversationTimelineWidget *tm = new GNUSocialApiConversationTimelineWidget(currentAccount(), url.host()); - connect(tm, SIGNAL(forwardReply(QString,QString,QString)), this, SIGNAL(reply(QString,QString,QString))); - connect(tm, SIGNAL(forwardResendPost(QString)), this, SIGNAL(resendPost(QString))); + connect(tm, &GNUSocialApiConversationTimelineWidget::forwardReply, this, &GNUSocialApiPostWidget::reply); + connect(tm, &GNUSocialApiConversationTimelineWidget::forwardResendPost, this, &GNUSocialApiPostWidget::resendPost); tm->show(); } else { TwitterApiPostWidget::checkAnchor(url); } } void GNUSocialApiPostWidget::slotResendPost() { QString text = generateResendText(); if (d->account->isChangeExclamationMark()) { int index = 0; while (true) { index = mGroupRegExp.indexIn(text, index); if (index != -1) { text.replace(index + 1, 1, d->account->changeExclamationMarkToText()); } else { break; } } } if ((Choqok::BehaviorSettings::resendWithQuickPost() || currentAccount()->isReadOnly()) && Choqok::UI::Global::quickPostWidget()) { Choqok::UI::Global::quickPostWidget()->setText(text); } else { Q_EMIT resendPost(text); } } diff --git a/helperlibs/gnusocialapihelper/gnusocialapisearch.cpp b/helperlibs/gnusocialapihelper/gnusocialapisearch.cpp index c9e3b77b..79cb482c 100644 --- a/helperlibs/gnusocialapihelper/gnusocialapisearch.cpp +++ b/helperlibs/gnusocialapihelper/gnusocialapisearch.cpp @@ -1,332 +1,333 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "gnusocialapisearch.h" #include #include #include #include "twitterapiaccount.h" #include "gnusocialapidebug.h" const QRegExp GNUSocialApiSearch::m_rId(QLatin1String("tag:.+,[\\d-]+:(\\d+)")); const QRegExp GNUSocialApiSearch::mIdRegExp(QLatin1String("(?:user|(?:.*notice))/([0-9]+)")); GNUSocialApiSearch::GNUSocialApiSearch(QObject *parent): TwitterApiSearch(parent) { qCDebug(CHOQOK); mSearchCode[ReferenceGroup] = QLatin1Char('!'); mSearchCode[ToUser] = QLatin1Char('@'); mSearchCode[FromUser].clear(); mSearchCode[ReferenceHashtag] = QLatin1Char('#'); mSearchTypes[ReferenceHashtag].first = i18nc("Dents are Identica posts", "Dents Including This Hashtag"); mSearchTypes[ReferenceHashtag].second = true; mSearchTypes[ReferenceGroup].first = i18nc("Dents are Identica posts", "Dents Including This Group"); mSearchTypes[ReferenceGroup].second = false; mSearchTypes[FromUser].first = i18nc("Dents are Identica posts", "Dents From This User"); mSearchTypes[FromUser].second = false; mSearchTypes[ToUser].first = i18nc("Dents are Identica posts", "Dents To This User"); mSearchTypes[ToUser].second = false; } GNUSocialApiSearch::~GNUSocialApiSearch() { } QUrl GNUSocialApiSearch::buildUrl(const SearchInfo &searchInfo, QString sinceStatusId, uint count, uint page) { qCDebug(CHOQOK); QString formattedQuery; switch (searchInfo.option) { case ToUser: formattedQuery = searchInfo.query + QLatin1String("/replies/rss"); break; case FromUser: formattedQuery = searchInfo.query + QLatin1String("/rss"); break; case ReferenceGroup: formattedQuery = QLatin1String("group/") + searchInfo.query + QLatin1String("/rss"); break; case ReferenceHashtag: formattedQuery = searchInfo.query; break; default: formattedQuery = searchInfo.query + QLatin1String("/rss"); break; }; QUrl url; TwitterApiAccount *theAccount = qobject_cast(searchInfo.account); Q_ASSERT(theAccount); if (searchInfo.option == ReferenceHashtag) { url = theAccount->apiUrl(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/search.atom")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("q"), formattedQuery); if (!sinceStatusId.isEmpty()) { urlQuery.addQueryItem(QLatin1String("since_id"), sinceStatusId); } int cntStr; if (count && count <= 100) { // GNU Social allows max 100 notices cntStr = count; } else { cntStr = 100; } urlQuery.addQueryItem(QLatin1String("rpp"), QString::number(cntStr)); if (page > 1) { urlQuery.addQueryItem(QLatin1String("page"), QString::number(page)); } url.setQuery(urlQuery); } else { url = QUrl(theAccount->apiUrl().url().remove(QLatin1String("/api"), Qt::CaseInsensitive)); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1Char('/') + (formattedQuery)); } return url; } void GNUSocialApiSearch::requestSearchResults(const SearchInfo &searchInfo, const QString &sinceStatusId, uint count, uint page) { qCDebug(CHOQOK); QUrl url = buildUrl(searchInfo, sinceStatusId, count, page); qCDebug(CHOQOK) << url; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCCritical(CHOQOK) << "Cannot create an http GET request!"; return; } mSearchJobs[job] = searchInfo; - connect(job, SIGNAL(result(KJob*)), this, SLOT(searchResultsReturned(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, + (void (GNUSocialApiSearch::*)(KJob*))&GNUSocialApiSearch::searchResultsReturned); job->start(); } void GNUSocialApiSearch::searchResultsReturned(KJob *job) { qCDebug(CHOQOK); if (job == 0) { qCDebug(CHOQOK) << "job is a null pointer"; Q_EMIT error(i18n("Unable to fetch search results.")); return; } SearchInfo info = mSearchJobs.take(job); if (job->error()) { qCCritical(CHOQOK) << "Error:" << job->errorString(); Q_EMIT error(i18n("Unable to fetch search results: %1", job->errorString())); return; } KIO::StoredTransferJob *jj = qobject_cast(job); QList postsList; if (info.option == ReferenceHashtag) { postsList = parseAtom(jj->data()); } else { postsList = parseRss(jj->data()); } qCDebug(CHOQOK) << "Emiting searchResultsReceived()"; Q_EMIT searchResultsReceived(info, postsList); } QString GNUSocialApiSearch::optionCode(int option) { return mSearchCode[option]; } QList< Choqok::Post * > GNUSocialApiSearch::parseAtom(const QByteArray &buffer) { QDomDocument document; QList statusList; document.setContent(buffer); QDomElement root = document.documentElement(); if (root.tagName() != QLatin1String("feed")) { qCDebug(CHOQOK) << "There is no feed element in Atom feed " << buffer.data(); return statusList; } QDomNode node = root.firstChild(); QString timeStr; while (!node.isNull()) { if (node.toElement().tagName() != QLatin1String("entry")) { node = node.nextSibling(); continue; } QDomNode entryNode = node.firstChild(); Choqok::Post *status = new Choqok::Post; status->isPrivate = false; while (!entryNode.isNull()) { QDomElement elm = entryNode.toElement(); if (elm.tagName() == QLatin1String("id")) { // Fomatting example: "tag:search.twitter.com,2005:1235016836" QString id; if (m_rId.exactMatch(elm.text())) { id = m_rId.cap(1); } /* sscanf( qPrintable( elm.text() ), "tag:search.twitter.com,%*d:%d", &id);*/ status->postId = id; } else if (elm.tagName() == QLatin1String("published")) { // Formatting example: "2009-02-21T19:42:39Z" // Need to extract date in similar fashion to dateFromString int year, month, day, hour, minute, second; sscanf(qPrintable(elm.text()), "%d-%d-%dT%d:%d:%d%*s", &year, &month, &day, &hour, &minute, &second); QDateTime recognized(QDate(year, month, day), QTime(hour, minute, second)); recognized.setTimeSpec(Qt::UTC); status->creationDateTime = recognized; } else if (elm.tagName() == QLatin1String("title")) { status->content = elm.text(); } else if (elm.tagName() == QLatin1String("link")) { if (elm.attribute(QLatin1String("rel")) == QLatin1String("related")) { status->author.profileImageUrl = QUrl::fromUserInput(elm.attribute(QLatin1String("href"))); } else if (elm.attribute(QLatin1String("rel")) == QLatin1String("alternate")) { status->link = QUrl::fromUserInput(elm.attribute(QLatin1String("href"))); } } else if (elm.tagName() == QLatin1String("author")) { QDomNode userNode = entryNode.firstChild(); while (!userNode.isNull()) { if (userNode.toElement().tagName() == QLatin1String("name")) { QString fullName = userNode.toElement().text(); int bracketPos = fullName.indexOf(QLatin1Char(' '), 0); QString screenName = fullName.left(bracketPos); QString name = fullName.right(fullName.size() - bracketPos - 2); name.chop(1); status->author.realName = name; status->author.userName = screenName; } userNode = userNode.nextSibling(); } } else if (elm.tagName() == QLatin1String("twitter:source")) { status->source = QUrl::fromPercentEncoding(elm.text().toLatin1()); } entryNode = entryNode.nextSibling(); } status->isFavorited = false; statusList.insert(0, status); node = node.nextSibling(); } return statusList; } QList< Choqok::Post * > GNUSocialApiSearch::parseRss(const QByteArray &buffer) { qCDebug(CHOQOK); QDomDocument document; QList statusList; document.setContent(buffer); QDomElement root = document.documentElement(); if (root.tagName() != QLatin1String("rdf:RDF")) { qCDebug(CHOQOK) << "There is no rdf:RDF element in RSS feed " << buffer.data(); return statusList; } QDomNode node = root.firstChild(); QString timeStr; while (!node.isNull()) { if (node.toElement().tagName() != QLatin1String("item")) { node = node.nextSibling(); continue; } Choqok::Post *status = new Choqok::Post; QDomAttr statusIdAttr = node.toElement().attributeNode(QLatin1String("rdf:about")); QString statusId; if (mIdRegExp.exactMatch(statusIdAttr.value())) { statusId = mIdRegExp.cap(1); } status->postId = statusId; QDomNode itemNode = node.firstChild(); while (!itemNode.isNull()) { if (itemNode.toElement().tagName() == QLatin1String("title")) { QString content = itemNode.toElement().text(); int nameSep = content.indexOf(QLatin1Char(':'), 0); QString screenName = content.left(nameSep); QString statusText = content.right(content.size() - nameSep - 2); status->author.userName = screenName; status->content = statusText; } else if (itemNode.toElement().tagName() == QLatin1String("dc:date")) { int year, month, day, hour, minute, second; sscanf(qPrintable(itemNode.toElement().text()), "%d-%d-%dT%d:%d:%d%*s", &year, &month, &day, &hour, &minute, &second); QDateTime recognized(QDate(year, month, day), QTime(hour, minute, second)); recognized.setTimeSpec(Qt::UTC); status->creationDateTime = recognized; } else if (itemNode.toElement().tagName() == QLatin1String("dc:creator")) { status->author.realName = itemNode.toElement().text(); } else if (itemNode.toElement().tagName() == QLatin1String("sioc:reply_of")) { QDomAttr userIdAttr = itemNode.toElement().attributeNode(QLatin1String("rdf:resource")); QString id; if (mIdRegExp.exactMatch(userIdAttr.value())) { id = mIdRegExp.cap(1); } status->replyToPostId = id; } else if (itemNode.toElement().tagName() == QLatin1String("statusnet:postIcon")) { QDomAttr imageAttr = itemNode.toElement().attributeNode(QLatin1String("rdf:resource")); status->author.profileImageUrl = QUrl::fromUserInput(imageAttr.value()); } else if (itemNode.toElement().tagName() == QLatin1String("link")) { // QDomAttr imageAttr = itemNode.toElement().attributeNode( "rdf:resource" ); status->link = QUrl::fromUserInput(itemNode.toElement().text()); } else if (itemNode.toElement().tagName() == QLatin1String("sioc:has_discussion")) { status->conversationId = itemNode.toElement().attributeNode(QLatin1String("rdf:resource")).value(); } itemNode = itemNode.nextSibling(); } status->isPrivate = false; status->isFavorited = false; statusList.insert(0, status); node = node.nextSibling(); } return statusList; } diff --git a/helperlibs/twitterapihelper/twitterapicomposerwidget.cpp b/helperlibs/twitterapihelper/twitterapicomposerwidget.cpp index 9583d9c9..5447e66e 100644 --- a/helperlibs/twitterapihelper/twitterapicomposerwidget.cpp +++ b/helperlibs/twitterapihelper/twitterapicomposerwidget.cpp @@ -1,79 +1,78 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapicomposerwidget.h" #include #include #include "choqokbehaviorsettings.h" #include "choqokuiglobal.h" #include "postwidget.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapitextedit.h" class TwitterApiComposerWidget::Private { public: Private() : model(0) {} QStringListModel *model; }; TwitterApiComposerWidget::TwitterApiComposerWidget(Choqok::Account *account, QWidget *parent) : Choqok::UI::ComposerWidget(account, parent), d(new Private) { qCDebug(CHOQOK); d->model = new QStringListModel(qobject_cast(account)->friendsList(), this); // d->index = new QModelIndex(d->model->rowCount(), 0, 0, d->model); // qCDebug(CHOQOK)<index; TwitterApiTextEdit *edit = new TwitterApiTextEdit(account, this); QCompleter *completer = new QCompleter(d->model, this); completer->setCaseSensitivity(Qt::CaseInsensitive); edit->setCompleter(completer); setEditor(edit); - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - SLOT(slotNewPostReady(Choqok::UI::PostWidget*,Choqok::Account*))); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &TwitterApiComposerWidget::slotNewPostReady); } TwitterApiComposerWidget::~TwitterApiComposerWidget() { delete d; } void TwitterApiComposerWidget::slotNewPostReady(Choqok::UI::PostWidget *widget, Choqok::Account *theAccount) { if (theAccount == currentAccount()) { QString name = widget->currentPost()->author.userName; if (!name.isEmpty() && !d->model->stringList().contains(name)) { int row = d->model->rowCount(); d->model->insertRow(row); d->model->setData(d->model->index(row), name); } } } diff --git a/helperlibs/twitterapihelper/twitterapidmessagedialog.cpp b/helperlibs/twitterapihelper/twitterapidmessagedialog.cpp index dc086809..b8499e16 100644 --- a/helperlibs/twitterapihelper/twitterapidmessagedialog.cpp +++ b/helperlibs/twitterapihelper/twitterapidmessagedialog.cpp @@ -1,194 +1,190 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapidmessagedialog.h" #include #include #include #include #include #include #include #include #include "choqoktextedit.h" #include "microblog.h" #include "notifymanager.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" class TwitterApiDMessageDialog::Private { public: Private(TwitterApiAccount *theAccount) : account(theAccount) {} QComboBox *comboFriendsList; Choqok::UI::TextEdit *editor; TwitterApiAccount *account; Choqok::Post *sentPost; }; TwitterApiDMessageDialog::TwitterApiDMessageDialog(TwitterApiAccount *theAccount, QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags), d(new Private(theAccount)) { setWindowTitle(i18n("Send Private Message")); setAttribute(Qt::WA_DeleteOnClose); setupUi(this); KConfigGroup grp(KSharedConfig::openConfig(), "TwitterApi"); resize(grp.readEntry("DMessageDialogSize", QSize(300, 200))); QStringList list = theAccount->followersList(); if (list.isEmpty()) { reloadFriendslist(); } else { list.sort(Qt::CaseInsensitive); d->comboFriendsList->addItems(list); } } TwitterApiDMessageDialog::~TwitterApiDMessageDialog() { KConfigGroup grp(KSharedConfig::openConfig(), "TwitterApi"); grp.writeEntry("DMessageDialogSize", size()); grp.sync(); delete d; } void TwitterApiDMessageDialog::setupUi(QWidget *mainWidget) { QLabel *lblTo = new QLabel(i18nc("Send message to", "To:"), this); d->comboFriendsList = new QComboBox(this); d->comboFriendsList->setDuplicatesEnabled(false); QPushButton *btnReload = new QPushButton(this); btnReload->setToolTip(i18n("Reload friends list")); btnReload->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); btnReload->setMaximumWidth(25); - connect(btnReload, SIGNAL(clicked(bool)), SLOT(reloadFriendslist())); + connect(btnReload, &QPushButton::clicked, this, &TwitterApiDMessageDialog::reloadFriendslist); QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget); QHBoxLayout *toLayout = new QHBoxLayout; toLayout->addWidget(lblTo); toLayout->addWidget(d->comboFriendsList); toLayout->addWidget(btnReload); mainLayout->addLayout(toLayout); d->editor = new Choqok::UI::TextEdit(d->account->postCharLimit()); - connect(d->editor, SIGNAL(returnPressed(QString)), SLOT(submitPost(QString))); + connect(d->editor, &Choqok::UI::TextEdit::returnPressed, this, &TwitterApiDMessageDialog::submitPost); mainLayout->addWidget(d->editor); d->editor->setFocus(); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); okButton->setText(i18nc("Send private message", "Send")); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &TwitterApiDMessageDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &TwitterApiDMessageDialog::reject); mainLayout->addWidget(buttonBox); } void TwitterApiDMessageDialog::setFriends(const QStringList friends) { d->comboFriendsList->clear(); d->comboFriendsList->addItems(friends); } Choqok::UI::TextEdit *TwitterApiDMessageDialog::editor() { return d->editor; } TwitterApiAccount *TwitterApiDMessageDialog::account() { return d->account; } void TwitterApiDMessageDialog::reloadFriendslist() { d->comboFriendsList->clear(); TwitterApiMicroBlog *blog = qobject_cast(d->account->microblog()); if (blog) { - connect(blog, SIGNAL(followersUsernameListed(TwitterApiAccount*,QStringList)), - this, SLOT(followersUsernameListed(TwitterApiAccount*,QStringList))); + connect(blog, &TwitterApiMicroBlog::followersUsernameListed, this, + &TwitterApiDMessageDialog::followersUsernameListed); blog->listFollowersUsername(d->account); d->comboFriendsList->setCurrentText(i18n("Please wait...")); } } void TwitterApiDMessageDialog::accept() { submitPost(d->editor->toPlainText()); } void TwitterApiDMessageDialog::submitPost(QString text) { if (d->account->friendsList().isEmpty() || text.isEmpty() || d->comboFriendsList->currentText().isEmpty()) { return; } hide(); - connect(d->account->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, - Choqok::MicroBlog::ErrorType, QString, Choqok::MicroBlog::ErrorLevel)), - this, - SLOT(errorPost(Choqok::Account *, Choqok::Post *, - Choqok::MicroBlog::ErrorType, QString, Choqok::MicroBlog::ErrorLevel))); + connect(d->account->microblog(), &Choqok::MicroBlog::errorPost, this, + &TwitterApiDMessageDialog::errorPost); connect(d->account->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(postCreated(Choqok::Account*,Choqok::Post*))); + this, SLOT(postCreated(Choqok::Account*,Choqok::Post*))); d->sentPost = new Choqok::Post; d->sentPost->isPrivate = true; d->sentPost->replyToUser.userName = d->comboFriendsList->currentText(); d->sentPost->content = text; d->account->microblog()->createPost(d->account, d->sentPost); } void TwitterApiDMessageDialog::followersUsernameListed(TwitterApiAccount *theAccount, QStringList list) { if (theAccount == d->account) { d->comboFriendsList->clear(); list.sort(Qt::CaseInsensitive); d->comboFriendsList->addItems(list); } } void TwitterApiDMessageDialog::errorPost(Choqok::Account *theAccount, Choqok::Post *thePost, Choqok::MicroBlog::ErrorType , QString , Choqok::MicroBlog::ErrorLevel) { if (theAccount == d->account && thePost == d->sentPost) { qCDebug(CHOQOK); show(); } } void TwitterApiDMessageDialog::setTo(const QString &username) { d->comboFriendsList->setCurrentText(username); } diff --git a/helperlibs/twitterapihelper/twitterapimicroblog.cpp b/helperlibs/twitterapihelper/twitterapimicroblog.cpp index 4b9782d3..9eaba183 100644 --- a/helperlibs/twitterapihelper/twitterapimicroblog.cpp +++ b/helperlibs/twitterapihelper/twitterapimicroblog.cpp @@ -1,1576 +1,1576 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapimicroblog.h" #include #include #include #include #include #include #include #include "account.h" #include "accountmanager.h" #include "application.h" #include "choqokappearancesettings.h" #include "choqokbehaviorsettings.h" #include "choqokuiglobal.h" #include "editaccountwidget.h" #include "microblogwidget.h" #include "notifymanager.h" #include "postwidget.h" #include "timelinewidget.h" #include "twitterapiaccount.h" #include "twitterapicomposerwidget.h" #include "twitterapidebug.h" #include "twitterapidmessagedialog.h" #include "twitterapipostwidget.h" #include "twitterapisearch.h" #include "twitterapisearchdialog.h" #include "twitterapisearchtimelinewidget.h" class TwitterApiMicroBlog::Private { public: Private(): countOfTimelinesToSave(0), friendsCursor(QLatin1String("-1")) { monthes[QLatin1String("Jan")] = 1; monthes[QLatin1String("Feb")] = 2; monthes[QLatin1String("Mar")] = 3; monthes[QLatin1String("Apr")] = 4; monthes[QLatin1String("May")] = 5; monthes[QLatin1String("Jun")] = 6; monthes[QLatin1String("Jul")] = 7; monthes[QLatin1String("Aug")] = 8; monthes[QLatin1String("Sep")] = 9; monthes[QLatin1String("Oct")] = 10; monthes[QLatin1String("Nov")] = 11; monthes[QLatin1String("Dec")] = 12; } int countOfTimelinesToSave; QString friendsCursor; QString followersCursor; QMap monthes; }; TwitterApiMicroBlog::TwitterApiMicroBlog(const QString &componentName, QObject *parent) : MicroBlog(componentName, parent), d(new Private) { qCDebug(CHOQOK); QStringList timelineTypes; timelineTypes << QLatin1String("Home") << QLatin1String("Reply") << QLatin1String("Inbox") << QLatin1String("Outbox") << QLatin1String("Favorite") << QLatin1String("ReTweets") << QLatin1String("Public"); setTimelineNames(timelineTypes); timelineApiPath[QLatin1String("Home")] = QLatin1String("/statuses/home_timeline.json"); timelineApiPath[QLatin1String("Reply")] = QLatin1String("/statuses/replies.json"); timelineApiPath[QLatin1String("Inbox")] = QLatin1String("/direct_messages.json"); timelineApiPath[QLatin1String("Outbox")] = QLatin1String("/direct_messages/sent.json"); timelineApiPath[QLatin1String("Favorite")] = QLatin1String("/favorites/list.json"); timelineApiPath[QLatin1String("ReTweets")] = QLatin1String("/statuses/retweets_of_me.json"); timelineApiPath[QLatin1String("Public")] = QLatin1String("/statuses/public_timeline.json"); setTimelineInfos(); } void TwitterApiMicroBlog::setTimelineInfos() { Choqok::TimelineInfo *t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Home"); t->description = i18nc("Timeline description", "You and your friends"); t->icon = QLatin1String("user-home"); mTimelineInfos[QLatin1String("Home")] = std::move(t); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Reply"); t->description = i18nc("Timeline description", "Replies to you"); t->icon = QLatin1String("edit-undo"); mTimelineInfos[QLatin1String("Reply")] = std::move(t); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Inbox"); t->description = i18nc("Timeline description", "Your incoming private messages"); t->icon = QLatin1String("mail-folder-inbox"); mTimelineInfos[QLatin1String("Inbox")] = std::move(t); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Outbox"); t->description = i18nc("Timeline description", "Private messages you have sent"); t->icon = QLatin1String("mail-folder-outbox"); mTimelineInfos[QLatin1String("Outbox")] = std::move(t); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Favorite"); t->description = i18nc("Timeline description", "Your favorites"); t->icon = QLatin1String("favorites"); mTimelineInfos[QLatin1String("Favorite")] = std::move(t); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Public"); t->description = i18nc("Timeline description", "Public timeline"); t->icon = QLatin1String("folder-green"); mTimelineInfos[QLatin1String("Public")] = std::move(t); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "ReTweets"); t->description = i18nc("Timeline description", "Your posts that were ReTweeted by others"); t->icon = QLatin1String("folder-red"); mTimelineInfos[QLatin1String("ReTweets")] = std::move(t); } TwitterApiMicroBlog::~TwitterApiMicroBlog() { qDeleteAll(mTimelineInfos); delete d; } QMenu *TwitterApiMicroBlog::createActionsMenu(Choqok::Account *theAccount, QWidget *parent) { QMenu *menu = MicroBlog::createActionsMenu(theAccount, parent); QAction *directMessge = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18n("Send Private Message..."), menu); directMessge->setData(theAccount->alias()); connect(directMessge, SIGNAL(triggered(bool)), SLOT(showDirectMessageDialog())); menu->addAction(directMessge); QAction *search = new QAction(QIcon::fromTheme(QLatin1String("edit-find")), i18n("Search..."), menu); search->setData(theAccount->alias()); connect(search, SIGNAL(triggered(bool)), SLOT(showSearchDialog())); menu->addAction(search); QAction *updateFriendsList = new QAction(QIcon::fromTheme(QLatin1String("arrow-down")), i18n("Update Friends List"), menu); updateFriendsList->setData(theAccount->alias()); - connect(updateFriendsList, SIGNAL(triggered(bool)), SLOT(slotUpdateFriendsList())); + connect(updateFriendsList, &QAction::triggered, this, &TwitterApiMicroBlog::slotUpdateFriendsList); menu->addAction(updateFriendsList); return menu; } QList< Choqok::Post * > TwitterApiMicroBlog::loadTimeline(Choqok::Account *account, const QString &timelineName) { QList< Choqok::Post * > list; if (timelineName.compare(QLatin1String("Favorite")) == 0) { return list; //NOTE Won't cache favorites, and this is for compatibility with older versions! } qCDebug(CHOQOK) << timelineName; QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); QStringList tmpList = postsBackup.groupList(); /// to don't load old archives if (tmpList.isEmpty() || !(QDateTime::fromString(tmpList.first()).isValid())) { return list; } ///-------------- QList groupList; for (const QString &str: tmpList) { groupList.append(QDateTime::fromString(str)); } qSort(groupList); int count = groupList.count(); if (count) { Choqok::Post *st = 0; for (int i = 0; i < count; ++i) { st = new Choqok::Post; KConfigGroup grp(&postsBackup, groupList[i].toString()); st->creationDateTime = grp.readEntry("creationDateTime", QDateTime::currentDateTime()); st->postId = grp.readEntry("postId", QString()); st->content = grp.readEntry("text", QString()); st->source = grp.readEntry("source", QString()); st->replyToPostId = grp.readEntry("inReplyToPostId", QString()); st->replyToUser.userId = grp.readEntry("inReplyToUserId", QString()); st->isFavorited = grp.readEntry("favorited", false); st->replyToUser.userName = grp.readEntry("inReplyToUserName", QString()); st->author.userId = grp.readEntry("authorId", QString()); st->author.userName = grp.readEntry("authorUserName", QString()); st->author.realName = grp.readEntry("authorRealName", QString()); st->author.homePageUrl = grp.readEntry("authorHomePageUrl", QUrl()); st->author.profileImageUrl = grp.readEntry("authorProfileImageUrl", QUrl()); st->author.description = grp.readEntry("authorDescription" , QString()); st->author.isProtected = grp.readEntry("isProtected", false); st->isPrivate = grp.readEntry("isPrivate" , false); st->author.location = grp.readEntry("authorLocation", QString()); st->link = postUrl(account, st->author.userName, st->postId); st->isRead = grp.readEntry("isRead", true); st->repeatedFromUser.userName = grp.readEntry("repeatedFrom", QString()); st->repeatedFromUser.homePageUrl = grp.readEntry("repeatedFromUserHomePage", QUrl()); st->repeatedPostId = grp.readEntry("repeatedPostId", QString()); st->repeatedDateTime = grp.readEntry("repeatedDateTime", QDateTime()); st->conversationId = grp.readEntry("conversationId", QString()); st->media = grp.readEntry("mediaUrl", QUrl()); st->quotedPost.postId = grp.readEntry("quotedPostId", QString()); st->quotedPost.user.profileImageUrl = grp.readEntry("quotedProfileUrl", QUrl()); st->quotedPost.content = grp.readEntry("quotedContent", QString()); st->quotedPost.user.userName = grp.readEntry("quotedUsername", QString()); list.append(st); } mTimelineLatestId[account][timelineName] = st->postId; } return list; } void TwitterApiMicroBlog::saveTimeline(Choqok::Account *account, const QString &timelineName, const QList< Choqok::UI::PostWidget * > &timeline) { if (timelineName.compare(QLatin1String("Favorite")) != 0) { qCDebug(CHOQOK); QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); ///Clear previous data: for (const QString &group: postsBackup.groupList()) { postsBackup.deleteGroup(group); } for (Choqok::UI::PostWidget *wd: timeline) { const Choqok::Post *post = (wd->currentPost()); KConfigGroup grp(&postsBackup, post->creationDateTime.toString()); grp.writeEntry("creationDateTime", post->creationDateTime); grp.writeEntry("postId", post->postId); grp.writeEntry("text", post->content); grp.writeEntry("source", post->source); grp.writeEntry("inReplyToPostId", post->replyToPostId); grp.writeEntry("inReplyToUserId", post->replyToUser.userId); grp.writeEntry("favorited", post->isFavorited); grp.writeEntry("inReplyToUserName", post->replyToUser.userName); grp.writeEntry("authorId", post->author.userId); grp.writeEntry("authorUserName", post->author.userName); grp.writeEntry("authorRealName", post->author.realName); grp.writeEntry("authorHomePageUrl", post->author.homePageUrl); grp.writeEntry("authorProfileImageUrl", post->author.profileImageUrl); grp.writeEntry("authorDescription" , post->author.description); grp.writeEntry("isPrivate" , post->isPrivate); grp.writeEntry("authorLocation" , post->author.location); grp.writeEntry("isProtected" , post->author.isProtected); grp.writeEntry("isRead" , post->isRead); grp.writeEntry("repeatedFrom", post->repeatedFromUser.userName); grp.writeEntry("repeatedFromUserHomePage", post->repeatedFromUser.homePageUrl); grp.writeEntry("repeatedPostId", post->repeatedPostId); grp.writeEntry("repeatedDateTime", post->repeatedDateTime); grp.writeEntry("conversationId", post->conversationId); grp.writeEntry("mediaUrl", post->media); grp.writeEntry("quotedPostId", post->quotedPost.postId); grp.writeEntry("quotedProfileUrl", post->quotedPost.user.profileImageUrl); grp.writeEntry("quotedContent", post->quotedPost.content); grp.writeEntry("quotedUsername", post->quotedPost.user.userName); } postsBackup.sync(); } if (Choqok::Application::isShuttingDown()) { --d->countOfTimelinesToSave; if (d->countOfTimelinesToSave < 1) { Q_EMIT readyForUnload(); } } } Choqok::UI::ComposerWidget *TwitterApiMicroBlog::createComposerWidget(Choqok::Account *account, QWidget *parent) { return new TwitterApiComposerWidget(account, parent); } TwitterApiSearchTimelineWidget *TwitterApiMicroBlog::createSearchTimelineWidget(Choqok::Account *theAccount, QString name, const SearchInfo &info, QWidget *parent) { return new TwitterApiSearchTimelineWidget(theAccount, name, info, parent); } void TwitterApiMicroBlog::createPost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QByteArray data; QVariantMap params; if (!post || post->content.isEmpty()) { qCDebug(CHOQOK) << "ERROR: Status text is empty!"; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::OtherError, i18n("Creating the new post failed. Text is empty."), MicroBlog::Critical); return; } if (!post->isPrivate) { ///Status Update QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/statuses/update.json")); params.insert(QLatin1String("status"), QUrl::toPercentEncoding(post->content)); if (!post->replyToPostId.isEmpty()) { params.insert(QLatin1String("in_reply_to_status_id"), post->replyToPostId.toLatin1()); } data = "status="; data += QUrl::toPercentEncoding(post->content); if (!post->replyToPostId.isEmpty()) { data += "&in_reply_to_status_id="; data += post->replyToPostId.toLatin1(); } if (!account->usingOAuth()) { data += "&source=Choqok"; } KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: application/x-www-form-urlencoded")); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation, params))); mCreatePostMap[ job ] = post; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotCreatePost); job->start(); } else {///Direct message QString recipientScreenName = post->replyToUser.userName; QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/direct_messages/new.json")); params.insert(QLatin1String("user"), recipientScreenName.toLocal8Bit()); params.insert(QLatin1String("text"), QUrl::toPercentEncoding(post->content)); data = "user="; data += recipientScreenName.toLocal8Bit(); data += "&text="; data += QUrl::toPercentEncoding(post->content); if (!account->usingOAuth()) { data += "&source=Choqok"; } KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; // QString errMsg = i18n ( "Creating the new post failed. Cannot create an http POST request. Please check your KDE installation." ); // emit errorPost ( theAccount, post, Choqok::MicroBlog::OtherError, errMsg, MicroBlog::Critical ); return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: application/x-www-form-urlencoded")); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation, params))); mCreatePostMap[ job ] = post; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotCreatePost); job->start(); } } void TwitterApiMicroBlog::repeatPost(Choqok::Account *theAccount, const QString &postId) { qCDebug(CHOQOK); if (postId.isEmpty()) { qCCritical(CHOQOK) << "ERROR: PostId is empty!"; return; } TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QStringLiteral("/statuses/retweet/%1.json").arg(postId)); QByteArray data; KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: application/x-www-form-urlencoded")); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); Choqok::Post *post = new Choqok::Post; post->postId = postId; mCreatePostMap[ job ] = post; mJobsAccount[job] = theAccount; connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotCreatePost); job->start(); } void TwitterApiMicroBlog::slotCreatePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = mCreatePostMap.take(job); Choqok::Account *theAccount = mJobsAccount.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Creating the new post failed: %1", job->errorString()), MicroBlog::Critical); } else { KIO::StoredTransferJob *stj = qobject_cast< KIO::StoredTransferJob * > (job); if (!post->isPrivate) { readPost(theAccount, stj->data(), post); if (post->isError) { QString errorMsg; errorMsg = checkForError(stj->data()); if (errorMsg.isEmpty()) { // We get the error message by parsing the JSON output, if there was a parsing error, then we don't have an error message, while there were still an error because of the error flag qCCritical(CHOQOK) << "Creating post: JSON parsing error:" << stj->data() ; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::ParsingError, i18n("Creating the new post failed. The result data could not be parsed."), MicroBlog::Critical); } else { qCCritical(CHOQOK) << "Server Error:" << errorMsg ; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::ServerError, i18n("Creating the new post failed, with error: %1", errorMsg), MicroBlog::Critical); } } else { Choqok::NotifyManager::success(i18n("New post submitted successfully")); Q_EMIT postCreated(theAccount, post); } } else { Choqok::NotifyManager::success(i18n("Private message sent successfully")); Q_EMIT postCreated(theAccount, post); } } } void TwitterApiMicroBlog::abortAllJobs(Choqok::Account *theAccount) { for (KJob *job: mJobsAccount.keys(theAccount)) { job->kill(KJob::EmitResult); } } void TwitterApiMicroBlog::abortCreatePost(Choqok::Account *theAccount, Choqok::Post *post) { if (mCreatePostMap.isEmpty()) { return; } if (post) { mCreatePostMap.key(post)->kill(KJob::EmitResult); } else { for (KJob *job: mCreatePostMap.keys()) { if (mJobsAccount[job] == theAccount) { job->kill(KJob::EmitResult); } } } } void TwitterApiMicroBlog::fetchPost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (!post || post->postId.isEmpty()) { return; } TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QStringLiteral("/statuses/show/%1.json").arg(post->postId)); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; // QString errMsg = i18n ( "Fetching the new post failed. Cannot create an HTTP GET request." // "Please check your KDE installation." ); // emit errorPost ( theAccount, post, Choqok::MicroBlog::OtherError, errMsg, Low ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mFetchPostMap[ job ] = post; mJobsAccount[ job ] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchPost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotFetchPost); job->start(); } void TwitterApiMicroBlog::slotFetchPost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCWarning(CHOQOK) << "NULL Job returned"; return; } Choqok::Post *post = mFetchPostMap.take(job); Choqok::Account *theAccount = mJobsAccount.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Fetching the new post failed. %1", job->errorString()), Low); } else { KIO::StoredTransferJob *stj = qobject_cast (job); readPost(theAccount, stj->data(), post); if (post->isError) { QString errorMsg; errorMsg = checkForError(stj->data()); if (errorMsg.isEmpty()) { qCDebug(CHOQOK) << "Parsing Error"; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::ParsingError, i18n("Fetching new post failed. The result data could not be parsed."), Low); } else { qCCritical(CHOQOK) << "Fetching post: Server Error:" << errorMsg; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::ServerError, i18n("Fetching new post failed, with error:%1", errorMsg), Low); } } else { post->isError = true; Q_EMIT postFetched(theAccount, post); } } } void TwitterApiMicroBlog::removePost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (!post->postId.isEmpty()) { TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); if (!post->isPrivate) { url.setPath(url.path() + QStringLiteral("/statuses/destroy/%1.json").arg(post->postId)); } else { url.setPath(url.path() + QStringLiteral("/direct_messages/destroy/%1.json").arg(post->postId)); } KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; // QString errMsg = i18n ( "Removing the post failed. Cannot create an HTTP POST request. Please check your KDE installation." ); // emit errorPost ( theAccount, post, Choqok::MicroBlog::OtherError, errMsg, MicroBlog::Critical ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mRemovePostMap[job] = post; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRemovePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRemovePost); job->start(); } } void TwitterApiMicroBlog::slotRemovePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer."; return; } Choqok::Post *post = mRemovePostMap.take(job); Choqok::Account *theAccount = mJobsAccount.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT errorPost(theAccount, post, CommunicationError, i18n("Removing the post failed. %1", job->errorString()), MicroBlog::Critical); } else { KIO::StoredTransferJob *stj = qobject_cast(job); QString errMsg = checkForError(stj->data()); if (errMsg.isEmpty()) { Q_EMIT postRemoved(theAccount, post); } else { qCCritical(CHOQOK) << "Server error on removing post:" << errMsg; Q_EMIT errorPost(theAccount, post, ServerError, i18n("Removing the post failed. %1", errMsg), MicroBlog::Critical); } } } void TwitterApiMicroBlog::createFavorite(Choqok::Account *theAccount, const QString &postId) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/favorites/create.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("id"), postId); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; // QString errMsg = i18n ( "The Favorite creation failed. Cannot create an http POST request. " // "Please check your KDE installation." ); // emit error ( theAccount, OtherError, errMsg ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mFavoriteMap[job] = postId; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreateFavorite(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotCreateFavorite); job->start(); } void TwitterApiMicroBlog::slotCreateFavorite(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer."; return; } Choqok::Account *theAccount = mJobsAccount.take(job); QString postId = mFavoriteMap.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Favorite creation failed. %1", job->errorString())); } else { KIO::StoredTransferJob *stJob = qobject_cast(job); QString err = checkForError(stJob->data()); if (!err.isEmpty()) { Q_EMIT error(theAccount, ServerError, err, Critical); return; } else { Q_EMIT favoriteCreated(theAccount, postId); } } } void TwitterApiMicroBlog::removeFavorite(Choqok::Account *theAccount, const QString &postId) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/favorites/destroy.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("id"), postId); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; // QString errMsg = i18n ( "Removing the favorite failed. Cannot create an http POST request. " // "Please check your KDE installation." ); // emit error ( theAccount, OtherError, errMsg ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mFavoriteMap[job] = postId; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRemoveFavorite(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRemoveFavorite); job->start(); } void TwitterApiMicroBlog::slotRemoveFavorite(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer."; return; } QString id = mFavoriteMap.take(job); Choqok::Account *theAccount = mJobsAccount.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Removing the favorite failed. %1", job->errorString())); } else { KIO::StoredTransferJob *stJob = qobject_cast(job); QString err = checkForError(stJob->data()); if (!err.isEmpty()) { Q_EMIT error(theAccount, ServerError, err, Critical); return; } else { Q_EMIT favoriteRemoved(theAccount, id); } } } void TwitterApiMicroBlog::listFriendsUsername(TwitterApiAccount *theAccount, bool active) { friendsList.clear(); d->friendsCursor = QLatin1String("-1"); if (theAccount) { requestFriendsScreenName(theAccount, active); } } void TwitterApiMicroBlog::requestFriendsScreenName(TwitterApiAccount *theAccount, bool active) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/friends/list.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("cursor"), d->friendsCursor); urlQuery.addQueryItem(QLatin1String("count"), QLatin1String("200")); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mJobsAccount[job] = theAccount; if (active) { - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRequestFriendsScreenNameActive(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRequestFriendsScreenNameActive); } else { - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRequestFriendsScreenNamePassive(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRequestFriendsScreenNamePassive); } job->start(); Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("Updating friends list for account %1...", theAccount->username())); } void TwitterApiMicroBlog::slotRequestFriendsScreenNameActive(KJob *job) { finishRequestFriendsScreenName(job, true); } void TwitterApiMicroBlog::slotRequestFriendsScreenNamePassive(KJob *job) { finishRequestFriendsScreenName(job, false); } void TwitterApiMicroBlog::finishRequestFriendsScreenName(KJob *job, bool active) { qCDebug(CHOQOK); TwitterApiAccount *theAccount = qobject_cast(mJobsAccount.take(job)); KIO::StoredTransferJob *stJob = qobject_cast(job); Choqok::MicroBlog::ErrorLevel level = active ? Critical : Low; if (stJob->error()) { Q_EMIT error(theAccount, ServerError, i18n("Friends list for account %1 could not be updated:\n%2", theAccount->username(), stJob->errorString()), level); return; } QStringList newList = readFriendsScreenName(theAccount, stJob->data()); newList.removeDuplicates(); if (! checkForError(stJob->data()).isEmpty()) { // if an error occurred, do not replace the friends list. theAccount->setFriendsList(friendsList); Q_EMIT friendsUsernameListed(theAccount, friendsList); } else if (QString::compare(d->friendsCursor, QLatin1String("0"))) { // if the cursor is not "0", there is more friends data to be had friendsList << newList; requestFriendsScreenName(theAccount, active); } else { friendsList << newList; theAccount->setFriendsList(friendsList); Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("Friends list for account %1 has been updated.", theAccount->username())); Q_EMIT friendsUsernameListed(theAccount, friendsList); } } void TwitterApiMicroBlog::listFollowersUsername(TwitterApiAccount* theAccount, bool active) { followersList.clear(); d->followersCursor = QLatin1String("-1"); if ( theAccount ) { requestFollowersScreenName(theAccount, active); } } void TwitterApiMicroBlog::requestFollowersScreenName(TwitterApiAccount* theAccount, bool active) { qCDebug(CHOQOK); TwitterApiAccount* account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/followers/list.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("cursor"), d->followersCursor); urlQuery.addQueryItem(QLatin1String("count"), QLatin1String("200")); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mJobsAccount[job] = theAccount; if (active) { - connect( job, SIGNAL( result( KJob* ) ), this, SLOT( slotRequestFollowersScreenNameActive(KJob*) ) ); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRequestFollowersScreenNameActive); } else { - connect( job, SIGNAL( result( KJob* ) ), this, SLOT( slotRequestFollowersScreenNamePassive(KJob*) ) ); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRequestFollowersScreenNamePassive); } job->start(); Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("Updating followers list for account %1...", theAccount->username())); } void TwitterApiMicroBlog::slotRequestFollowersScreenNameActive(KJob* job) { finishRequestFollowersScreenName(job, true); } void TwitterApiMicroBlog::slotRequestFollowersScreenNamePassive(KJob* job) { finishRequestFollowersScreenName(job, false); } void TwitterApiMicroBlog::finishRequestFollowersScreenName(KJob* job, bool active) { qCDebug(CHOQOK); TwitterApiAccount *theAccount = qobject_cast( mJobsAccount.take(job) ); KIO::StoredTransferJob* stJob = qobject_cast( job ); Choqok::MicroBlog::ErrorLevel level = active ? Critical : Low; if (stJob->error()) { Q_EMIT error(theAccount, ServerError, i18n("Followers list for account %1 could not be updated:\n%2", theAccount->username(), stJob->errorString()), level); return; } QStringList newList = readFollowersScreenName(theAccount, stJob->data()); newList.removeDuplicates(); if (!checkForError(stJob->data()).isEmpty()) { // if an error occurred, do not replace the friends list. theAccount->setFollowersList(followersList); Q_EMIT followersUsernameListed(theAccount, followersList); } else if (QString::compare(d->followersCursor, QLatin1String("0"))) { // if the cursor is not "0", there is more friends data to be had followersList << newList; requestFollowersScreenName(theAccount, active); } else { followersList << newList; theAccount->setFollowersList(followersList); Choqok::UI::Global::mainWindow()->showStatusMessage(i18n("Followers list for account %1 has been updated.", theAccount->username()) ); Q_EMIT followersUsernameListed(theAccount, followersList); } } void TwitterApiMicroBlog::updateTimelines(Choqok::Account *theAccount) { qCDebug(CHOQOK); for (const QString &tm: theAccount->timelineNames()) { requestTimeLine(theAccount, tm, mTimelineLatestId[theAccount][tm]); } } void TwitterApiMicroBlog::requestTimeLine(Choqok::Account *theAccount, QString type, QString latestStatusId, int page, QString maxId) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + timelineApiPath[type]); QUrlQuery urlQuery; // needed because lists have different parameter names but // returned timelines have the same JSON format if (timelineApiPath[type].contains(QLatin1String("lists/statuses"))) { // type contains @username/timelinename const QString slug = type.mid(type.indexOf(QLatin1String("/")) + 1); urlQuery.addQueryItem(QLatin1String("slug"), slug); const QString owner = type.mid(1, type.indexOf(QLatin1String("/")) - 1); urlQuery.addQueryItem(QLatin1String("owner_screen_name"), owner); } else { int countOfPost = Choqok::BehaviorSettings::countOfPosts(); if (!latestStatusId.isEmpty()) { urlQuery.addQueryItem(QLatin1String("since_id"), latestStatusId); countOfPost = 200; } urlQuery.addQueryItem(QLatin1String("count"), QString::number(countOfPost)); if (!maxId.isEmpty()) { urlQuery.addQueryItem(QLatin1String("max_id"), maxId); } if (page) { urlQuery.addQueryItem(QLatin1String("page"), QString::number(page)); } } url.setQuery(urlQuery); qCDebug(CHOQOK) << "Latest" << type << "Id:" << latestStatusId;// << "apiReq:" << url; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; // QString errMsg = i18n ( "Cannot create an http GET request. Please check your KDE installation." ); // emit error ( theAccount, OtherError, errMsg, Low ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mRequestTimelineMap[job] = type; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRequestTimeline(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotRequestTimeline); job->start(); } void TwitterApiMicroBlog::slotRequestTimeline(KJob *job) { qCDebug(CHOQOK);//TODO Add error detection if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *theAccount = mJobsAccount.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Timeline update failed: %1", job->errorString()), Low); return; } QString type = mRequestTimelineMap.take(job); if (isValidTimeline(type)) { KIO::StoredTransferJob *j = qobject_cast(job); QList list; if (type == QLatin1String("Inbox") || type == QLatin1String("Outbox")) { list = readDirectMessages(theAccount, j->data()); } else { list = readTimeline(theAccount, j->data()); } if (!list.isEmpty()) { mTimelineLatestId[theAccount][type] = list.last()->postId; Q_EMIT timelineDataReceived(theAccount, type, list); } } } QByteArray TwitterApiMicroBlog::authorizationHeader(TwitterApiAccount *theAccount, const QUrl &requestUrl, QNetworkAccessManager::Operation method, const QVariantMap ¶ms) { QByteArray auth; if (theAccount->usingOAuth()) { auth = theAccount->oauthInterface()->authorizationHeader(requestUrl, method, params); } else { auth = theAccount->username().toUtf8() + ':' + theAccount->password().toUtf8(); auth = auth.toBase64().prepend("Basic "); } return auth; } void TwitterApiMicroBlog::setRepeatedOfInfo(Choqok::Post *post, Choqok::Post *repeatedPost) { post->content = repeatedPost->content; post->replyToPostId = repeatedPost->replyToPostId; post->replyToUser.userId = repeatedPost->replyToUser.userId; post->replyToUser.userName = repeatedPost->replyToUser.userName; post->repeatedPostId = repeatedPost->postId; post->repeatedDateTime = repeatedPost->creationDateTime; if (Choqok::AppearanceSettings::showRetweetsInChoqokWay()) { post->repeatedFromUser.userName = repeatedPost->author.userName; post->repeatedFromUser.homePageUrl = repeatedPost->author.homePageUrl; } else { post->repeatedFromUser.userName = post->author.userName; post->repeatedFromUser.homePageUrl = post->author.homePageUrl; post->author = repeatedPost->author; } if (!repeatedPost->quotedPost.content.isEmpty()) { post->quotedPost = repeatedPost->quotedPost; } } void TwitterApiMicroBlog::setQuotedPost(Choqok::Post* post, Choqok::Post* quotedPost) { post->quotedPost.user.profileImageUrl = quotedPost->author.profileImageUrl; post->quotedPost.user.userName = quotedPost->author.userName; post->quotedPost.postId = quotedPost->postId; post->quotedPost.content = quotedPost->content; } QDateTime TwitterApiMicroBlog::dateFromString(const QString &date) { char s[10]; int year, day, hours, minutes, seconds, tz; sscanf(qPrintable(date), "%*s %s %d %d:%d:%d %d %d", s, &day, &hours, &minutes, &seconds, &tz, &year); int month = d->monthes[QLatin1String(s)]; QDateTime recognized(QDate(year, month, day), QTime(hours, minutes, seconds)); if (tz == 0) { //tz is the timezone, in Twitter it's always UTC(0) in Identica it's local +/-NUMBER recognized.setTimeSpec(Qt::UTC); } return recognized.toLocalTime(); } void TwitterApiMicroBlog::aboutToUnload() { d->countOfTimelinesToSave = 0; for (Choqok::Account *acc: Choqok::AccountManager::self()->accounts()) { if (acc->microblog() == this) { d->countOfTimelinesToSave += acc->timelineNames().count(); } } Q_EMIT saveTimelines(); } void TwitterApiMicroBlog::showDirectMessageDialog(TwitterApiAccount *theAccount, const QString &toUsername) { qCDebug(CHOQOK); if (!theAccount) { QAction *act = qobject_cast(sender()); theAccount = qobject_cast( Choqok::AccountManager::self()->findAccount(act->data().toString())); } TwitterApiDMessageDialog *dmsg = new TwitterApiDMessageDialog(theAccount, Choqok::UI::Global::mainWindow()); if (!toUsername.isEmpty()) { dmsg->setTo(toUsername); } dmsg->show(); } Choqok::TimelineInfo *TwitterApiMicroBlog::timelineInfo(const QString &timelineName) { if (isValidTimeline(timelineName)) { return mTimelineInfos.value(timelineName); } else { return nullptr; } } void TwitterApiMicroBlog::showSearchDialog(TwitterApiAccount *theAccount) { if (!theAccount) { QAction *act = qobject_cast(sender()); theAccount = qobject_cast( Choqok::AccountManager::self()->findAccount(act->data().toString())); } QPointer searchDlg = new TwitterApiSearchDialog(theAccount, Choqok::UI::Global::mainWindow()); searchDlg->show(); } void TwitterApiMicroBlog::slotUpdateFriendsList() { QAction *act = qobject_cast(sender()); TwitterApiAccount *theAccount = qobject_cast( Choqok::AccountManager::self()->findAccount(act->data().toString())); listFriendsUsername(theAccount, true); } void TwitterApiMicroBlog::createFriendship(Choqok::Account *theAccount, const QString &username) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/friendships/create.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("screen_name"), username); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; qCDebug(CHOQOK) << url; if (!job) { qCCritical(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mJobsAccount[job] = theAccount; mFriendshipMap[ job ] = username; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreateFriendship(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotCreateFriendship); job->start(); } void TwitterApiMicroBlog::slotCreateFriendship(KJob *job) { qCDebug(CHOQOK); if (!job) { qCCritical(CHOQOK) << "Job is a null Pointer!"; return; } TwitterApiAccount *theAccount = qobject_cast(mJobsAccount.take(job)); QString username = mFriendshipMap.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Creating friendship with %1 failed. %2", username, job->errorString())); return; } KIO::StoredTransferJob *stj = qobject_cast(job); Choqok::User *user = readUserInfo(stj->data()); if (user /*&& user->userName.compare(username, Qt::CaseInsensitive)*/) { Q_EMIT friendshipCreated(theAccount, username); Choqok::NotifyManager::success(i18n("You are now listening to %1's posts.", username)); theAccount->setFriendsList(QStringList()); listFriendsUsername(theAccount); } else { QString errorMsg = checkForError(stj->data()); if (errorMsg.isEmpty()) { qCDebug(CHOQOK) << "Parse Error:" << stj->data(); Q_EMIT error(theAccount, ParsingError, i18n("Creating friendship with %1 failed: the server returned invalid data.", username)); } else { qCDebug(CHOQOK) << "Server error:" << errorMsg; Q_EMIT error(theAccount, ServerError, i18n("Creating friendship with %1 failed: %2", username, errorMsg)); } } } void TwitterApiMicroBlog::destroyFriendship(Choqok::Account *theAccount, const QString &username) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/friendships/destroy.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("screen_name"), username); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mJobsAccount[job] = theAccount; mFriendshipMap[ job ] = username; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotDestroyFriendship(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotDestroyFriendship); job->start(); } void TwitterApiMicroBlog::slotDestroyFriendship(KJob *job) { qCDebug(CHOQOK); if (!job) { qCCritical(CHOQOK) << "Job is a null Pointer!"; return; } TwitterApiAccount *theAccount = qobject_cast(mJobsAccount.take(job)); QString username = mFriendshipMap.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Destroying friendship with %1 failed. %2", username, job->errorString())); return; } KIO::StoredTransferJob *stj = qobject_cast(job); Choqok::User *user = readUserInfo(stj->data()); if (user /*&& user->userName.compare( username, Qt::CaseInsensitive )*/) { Q_EMIT friendshipDestroyed(theAccount, username); Choqok::NotifyManager::success(i18n("You will not receive %1's updates.", username)); theAccount->setFriendsList(QStringList()); listFriendsUsername(theAccount); } else { QString errorMsg = checkForError(stj->data()); if (errorMsg.isEmpty()) { qCDebug(CHOQOK) << "Parse Error:" << stj->data(); Q_EMIT error(theAccount, ParsingError, i18n("Destroying friendship with %1 failed: the server returned invalid data.", username)); } else { qCDebug(CHOQOK) << "Server error:" << errorMsg; Q_EMIT error(theAccount, ServerError, i18n("Destroying friendship with %1 failed: %2", username, errorMsg)); } } } void TwitterApiMicroBlog::blockUser(Choqok::Account *theAccount, const QString &username) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QLatin1String("/blocks/create.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("screen_name"), username); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mJobsAccount[job] = theAccount; mFriendshipMap[ job ] = username; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotBlockUser(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotBlockUser); job->start(); } void TwitterApiMicroBlog::reportUserAsSpam(Choqok::Account *theAccount, const QString &username) { qCDebug(CHOQOK); TwitterApiAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1String("/users/report_spam.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("screen_name"), username); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedHttpPost(QByteArray(), url, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mJobsAccount[job] = theAccount; mFriendshipMap[ job ] = username; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotReportUser(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiMicroBlog::slotReportUser); job->start(); } void TwitterApiMicroBlog::slotBlockUser(KJob *job) { qCDebug(CHOQOK); if (!job) { qCCritical(CHOQOK) << "Job is a null Pointer!"; return; } Choqok::Account *theAccount = mJobsAccount.take(job); QString username = mFriendshipMap.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Blocking %1 failed. %2", username, job->errorString())); return; } Choqok::User *user = readUserInfo(qobject_cast(job)->data()); if (user /*&& user->userName.compare( username, Qt::CaseInsensitive )*/) { Q_EMIT userBlocked(theAccount, username); Choqok::NotifyManager::success(i18n("You will no longer be disturbed by %1.", username)); } else { qCDebug(CHOQOK) << "Parse Error:" << qobject_cast(job)->data(); Q_EMIT error(theAccount, ParsingError, i18n("Blocking %1 failed: the server returned invalid data.", username)); } //TODO Check for failor! } void TwitterApiMicroBlog::slotReportUser(KJob *job) { qCDebug(CHOQOK); if (!job) { qCCritical(CHOQOK) << "Job is a null Pointer!"; return; } Choqok::Account *theAccount = mJobsAccount.take(job); QString username = mFriendshipMap.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, CommunicationError, i18n("Reporting %1 failed. %2", username, job->errorString())); return; } Choqok::User *user = readUserInfo(qobject_cast(job)->data()); if (user) { Choqok::NotifyManager::success(i18n("Report sent successfully")); } else { qCDebug(CHOQOK) << "Parse Error:" << qobject_cast(job)->data(); Q_EMIT error(theAccount, ParsingError, i18n("Reporting %1 failed: the server returned invalid data.", username)); } } ///=================================================================== QString TwitterApiMicroBlog::checkForError(const QByteArray &buffer) { const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); if (map.contains(QLatin1String("errors"))) { QStringList errors; for (const QVariant &msg: map[QLatin1String("errors")].toList()) { errors.append(msg.toMap()[QLatin1String("message")].toString()); qCCritical(CHOQOK) << "Error:" << errors.last(); } return errors.join(QLatin1Char(';')); } } return QString(); } QList< Choqok::Post * > TwitterApiMicroBlog::readTimeline(Choqok::Account *theAccount, const QByteArray &buffer) { QList postList; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { for (const QVariant &list: json.toVariant().toList()) { Choqok::Post *post = readPost(theAccount, list.toMap(), new Choqok::Post); if (post) { postList.prepend(post); } } } else { const QString err = checkForError(buffer); if (err.isEmpty()) { qCCritical(CHOQOK) << "JSON parsing failed.\nBuffer was: \n" << buffer; Q_EMIT error(theAccount, ParsingError, i18n("Could not parse the data that has been received from the server.")); } else { Q_EMIT error(theAccount, ServerError, err); } } return postList; } Choqok::Post *TwitterApiMicroBlog::readPost(Choqok::Account *theAccount, const QByteArray &buffer, Choqok::Post *post) { const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { return readPost(theAccount, json.toVariant().toMap(), post); } else { if (!post) { qCCritical(CHOQOK) << "TwitterApiMicroBlog::readPost: post is NULL!"; post = new Choqok::Post; } Q_EMIT errorPost(theAccount, post, ParsingError, i18n("Could not parse the data that has been received from the server.")); qCCritical(CHOQOK) << "JSon parsing failed. Buffer was:" << buffer; post->isError = true; return post; } } Choqok::Post *TwitterApiMicroBlog::readPost(Choqok::Account *theAccount, const QVariantMap &var, Choqok::Post *post) { if (!post) { qCCritical(CHOQOK) << "TwitterApiMicroBlog::readPost: post is NULL!"; return nullptr; } post->content = var[QLatin1String("text")].toString(); post->creationDateTime = dateFromString(var[QLatin1String("created_at")].toString()); post->isFavorited = var[QLatin1String("favorited")].toBool(); post->postId = var[QLatin1String("id")].toString(); post->replyToPostId = var[QLatin1String("in_reply_to_status_id")].toString(); post->replyToUser.userId = var[QLatin1String("in_reply_to_user_id")].toString(); post->replyToUser.userName = var[QLatin1String("in_reply_to_screen_name")].toString(); post->source = var[QLatin1String("source")].toString(); QVariantMap userMap = var[QLatin1String("user")].toMap(); post->author.description = userMap[QLatin1String("description")].toString(); post->author.location = userMap[QLatin1String("location")].toString(); post->author.realName = userMap[QLatin1String("name")].toString(); post->author.userId = userMap[QLatin1String("id")].toString(); post->author.userName = userMap[QLatin1String("screen_name")].toString(); post->author.profileImageUrl = userMap[QLatin1String("profile_image_url")].toUrl(); QVariantMap entities = var[QLatin1String("entities")].toMap(); QVariantMap mediaMap; QVariantList media = entities[QLatin1String("media")].toList(); if (media.size() > 0) { mediaMap = media.at(0).toMap(); post->media = QUrl::fromUserInput(mediaMap[QLatin1String("media_url")].toString() + QLatin1String(":small")); QVariantMap sizes = mediaMap[QLatin1String("sizes")].toMap(); QVariantMap w = sizes[QLatin1String("small")].toMap(); } else { post->media = QUrl(); } QVariantMap retweetedMap = var[QLatin1String("retweeted_status")].toMap(); if (!retweetedMap.isEmpty()) { Choqok::Post *retweetedPost = readPost(theAccount, retweetedMap, new Choqok::Post); setRepeatedOfInfo(post, retweetedPost); delete retweetedPost; } QVariantMap quotedMap = var[QLatin1String("quoted_status")].toMap(); if (!quotedMap.isEmpty()) { Choqok::Post *quotedPost = readPost(theAccount, quotedMap, new Choqok::Post); setQuotedPost(post, quotedPost); delete quotedPost; } post->link = postUrl(theAccount, post->author.userName, post->postId); post->isRead = post->isFavorited || (post->repeatedFromUser.userName.compare(theAccount->username(), Qt::CaseInsensitive) == 0); if(post->postId.isEmpty() || post->author.userName.isEmpty()) post->isError = true; return post; } QList< Choqok::Post * > TwitterApiMicroBlog::readDirectMessages(Choqok::Account *theAccount, const QByteArray &buffer) { QList postList; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { for (const QVariant &list: json.toVariant().toList()) { postList.prepend(readDirectMessage(theAccount, list.toMap())); } } else { const QString err = checkForError(buffer); if (err.isEmpty()) { qCCritical(CHOQOK) << "JSON parsing failed.\nBuffer was: \n" << buffer; Q_EMIT error(theAccount, ParsingError, i18n("Could not parse the data that has been received from the server.")); } else { Q_EMIT error(theAccount, ServerError, err); } } return postList; } Choqok::Post *TwitterApiMicroBlog::readDirectMessage(Choqok::Account *theAccount, const QByteArray &buffer) { const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { return readDirectMessage(theAccount, json.toVariant().toMap()); } else { Choqok::Post *post = new Choqok::Post; post->isError = true; return post; } } Choqok::Post *TwitterApiMicroBlog::readDirectMessage(Choqok::Account *theAccount, const QVariantMap &var) { Choqok::Post *msg = new Choqok::Post; msg->isPrivate = true; QString senderId, recipientId, senderScreenName, recipientScreenName, senderName, senderDescription, recipientName, recipientDescription; QUrl senderProfileImageUrl, recipientProfileImageUrl; msg->creationDateTime = dateFromString(var[QLatin1String("created_at")].toString()); msg->content = var[QLatin1String("text")].toString(); msg->postId = var[QLatin1String("id")].toString();; senderId = var[QLatin1String("sender_id")].toString(); recipientId = var[QLatin1String("recipient_id")].toString(); senderScreenName = var[QLatin1String("sender_screen_name")].toString(); recipientScreenName = var[QLatin1String("recipient_screen_name")].toString(); QVariantMap sender = var[QLatin1String("sender")].toMap(); senderProfileImageUrl = sender[QLatin1String("profile_image_url")].toUrl(); senderName = sender[QLatin1String("name")].toString(); senderDescription = sender[QLatin1String("description")].toString(); QVariantMap recipient = var[QLatin1String("recipient")].toMap(); recipientProfileImageUrl = recipient[QLatin1String("profile_image_url")].toUrl(); recipientName = recipient[QLatin1String("name")].toString(); recipientDescription = recipient[QLatin1String("description")].toString(); if (senderScreenName.compare(theAccount->username(), Qt::CaseInsensitive) == 0) { msg->author.description = recipientDescription; msg->author.userName = recipientScreenName; msg->author.profileImageUrl = recipientProfileImageUrl; msg->author.realName = recipientName; msg->author.userId = recipientId; msg->replyToUser.userId = recipientId; msg->replyToUser.userName = recipientScreenName; msg->isRead = true; } else { msg->author.description = senderDescription; msg->author.userName = senderScreenName; msg->author.profileImageUrl = senderProfileImageUrl; msg->author.realName = senderName; msg->author.userId = senderId; msg->replyToUser.userId = recipientId; msg->replyToUser.userName = recipientScreenName; } return msg; } Choqok::User *TwitterApiMicroBlog::readUserInfo(const QByteArray &buffer) { Choqok::User *user = nullptr; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { user = new Choqok::User(readUser(0, json.toVariant().toMap())); } else { QString err = i18n("Retrieving the friends list failed. The data returned from the server is corrupted."); qCDebug(CHOQOK) << "JSON parse error:the buffer is: \n" << buffer; Q_EMIT error(0, ParsingError, err, Critical); } return user; } QStringList TwitterApiMicroBlog::readFriendsScreenName(Choqok::Account *theAccount, const QByteArray &buffer) { QStringList list; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); QVariantList jsonList = map[QLatin1String("users")].toList(); QString nextCursor = map[QLatin1String("next_cursor_str")].toString(); if (nextCursor.isEmpty()) { nextCursor = QLatin1String("0"); // we probably ran the rate limit; stop bugging the server already } for (const QVariant &user: jsonList) { list << user.toMap()[QLatin1String("screen_name")].toString(); } d->friendsCursor = nextCursor; } else { QString err = i18n("Retrieving the friends list failed. The data returned from the server is corrupted."); qCDebug(CHOQOK) << "JSON parse error:the buffer is: \n" << buffer; Q_EMIT error(theAccount, ParsingError, err, Critical); } return list; } QStringList TwitterApiMicroBlog::readFollowersScreenName(Choqok::Account *theAccount, const QByteArray &buffer) { QStringList list; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); QVariantList jsonList = map[QLatin1String("users")].toList(); QString nextCursor = map[QLatin1String("next_cursor_str")].toString(); if (nextCursor.isEmpty()) { nextCursor = QLatin1String("0"); // we probably ran the rate limit; stop bugging the server already } for (const QVariant &user: jsonList) { list << user.toMap()[QLatin1String("screen_name")].toString(); } d->followersCursor = nextCursor; } else { QString err = i18n("Retrieving the followers list failed. The data returned from the server is corrupted."); qCDebug(CHOQOK) << "JSON parse error:the buffer is: \n" << buffer; Q_EMIT error(theAccount, ParsingError, err, Critical); } return list; } Choqok::User TwitterApiMicroBlog::readUser(Choqok::Account *theAccount, const QVariantMap &map) { Q_UNUSED(theAccount); Choqok::User u; u.description = map[QLatin1String("description")].toString(); u.homePageUrl = map[QLatin1String("url")].toUrl(); u.isProtected = map[QLatin1String("protected")].toBool(); u.location = map[QLatin1String("location")].toString(); u.profileImageUrl = map[QLatin1String("profile_image_url")].toUrl(); u.realName = map[QLatin1String("name")].toString(); u.userId = map[QLatin1String("id_str")].toString(); u.userName = map[QLatin1String("screen_name")].toString(); return u; } diff --git a/helperlibs/twitterapihelper/twitterapimicroblogwidget.cpp b/helperlibs/twitterapihelper/twitterapimicroblogwidget.cpp index c58ca0b6..6f2334dc 100644 --- a/helperlibs/twitterapihelper/twitterapimicroblogwidget.cpp +++ b/helperlibs/twitterapihelper/twitterapimicroblogwidget.cpp @@ -1,293 +1,289 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapimicroblogwidget.h" #include #include #include #include #include #include #include #include #include "account.h" #include "composerwidget.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" #include "twitterapisearchtimelinewidget.h" class TwitterApiMicroBlogWidget::Private { public: Private(Choqok::Account *acc) : btnCloseSearch(0) { qCDebug(CHOQOK); mBlog = qobject_cast(acc->microblog()); this->account = qobject_cast(acc); } TwitterApiMicroBlog *mBlog; TwitterApiAccount *account; QToolButton *btnCloseSearch; }; QIcon addTextToIcon(const QIcon &icon, const QString &text, const QSize &result_size , const QPalette &palette) { QIcon result; QPixmap pixmap = icon.pixmap(result_size); QPainter painter(&pixmap); QFont font; font.setWeight(result_size.height() / 3); font.setBold(true); painter.setFont(font); int textWidth = painter.fontMetrics().width(text); QRect rct(0 , 0 , textWidth , result_size.height() / 2); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(palette.color(QPalette::Active , QPalette::HighlightedText)); painter.drawText(rct , Qt::AlignTop | Qt::AlignLeft , text); result.addPixmap(pixmap , QIcon::Active); return result; } TwitterApiMicroBlogWidget::TwitterApiMicroBlogWidget(Choqok::Account *account, QWidget *parent) : MicroBlogWidget(account, parent), d(new Private(account)) { qCDebug(CHOQOK); - connect(account, SIGNAL(modified(Choqok::Account*)), - this, SLOT(slotAccountModified(Choqok::Account*))); - connect(d->mBlog->searchBackend(), - SIGNAL(searchResultsReceived(SearchInfo,QList&)), - SLOT(slotSearchResultsReceived(SearchInfo,QList&))); - connect(d->mBlog, SIGNAL(saveTimelines()), SLOT(saveSearchTimelinesState())); + connect(account, &Choqok::Account::modified, this, &TwitterApiMicroBlogWidget::slotAccountModified); + connect(d->mBlog->searchBackend(), &TwitterApiSearch::searchResultsReceived, + this, &TwitterApiMicroBlogWidget::slotSearchResultsReceived); + connect(d->mBlog, &TwitterApiMicroBlog::saveTimelines, this, + &TwitterApiMicroBlogWidget::saveSearchTimelinesState); loadSearchTimelinesState(); } void TwitterApiMicroBlogWidget::initUi() { qCDebug(CHOQOK); Choqok::UI::MicroBlogWidget::initUi(); - connect(timelinesTabWidget(), SIGNAL(contextMenu(QWidget*,QPoint)), - this, SLOT(slotContextMenu(QWidget*,QPoint))); + connect(timelinesTabWidget(), (void (Choqok::UI::ChoqokTabBar::*)(QWidget*,const QPoint&))&Choqok::UI::ChoqokTabBar::contextMenu, + this, &TwitterApiMicroBlogWidget::slotContextMenu); // connect(timelinesTabWidget(), SIGNAL(currentChanged(int)), SLOT(slotCurrentTimelineChanged(int)) ); // d->btnCloseSearch->setIcon(QIcon::fromTheme("tab-close")); // d->btnCloseSearch->setAutoRaise(true); // d->btnCloseSearch->setToolTip(i18nc("Close a timeline", "Close Timeline")); // d->btnCloseSearch->setFixedWidth( 32 ); // timelinesTabWidget()->setTabAlongsideWidget( d->btnCloseSearch ); // connect(d->btnCloseSearch, SIGNAL(clicked(bool)), SLOT(slotCloseCurrentSearch()) ); // slotCurrentTimelineChanged(timelinesTabWidget()->currentIndex()); } TwitterApiMicroBlogWidget::~TwitterApiMicroBlogWidget() { delete d; } void TwitterApiMicroBlogWidget::slotSearchResultsReceived(const SearchInfo &info, QList< Choqok::Post * > &postsList) { qCDebug(CHOQOK); if (info.account == currentAccount()) { qCDebug(CHOQOK) << postsList.count(); QString name = QStringLiteral("%1%2").arg(d->mBlog->searchBackend()->optionCode(info.option)).arg(info.query); if (mSearchTimelines.contains(name)) { mSearchTimelines.value(name)->addNewPosts(postsList); } else { if (postsList.isEmpty()) { addSearchTimelineWidgetToUi(name, info)->addPlaceholderMessage(i18n("(The search result is empty.)")); } else { addSearchTimelineWidgetToUi(name, info)->addNewPosts(postsList); } } } } TwitterApiSearchTimelineWidget *TwitterApiMicroBlogWidget::addSearchTimelineWidgetToUi(const QString &name, const SearchInfo &info) { qCDebug(CHOQOK); TwitterApiSearchTimelineWidget *mbw = d->mBlog->createSearchTimelineWidget(currentAccount(), name, info, this); if (mbw) { mbw->setObjectName(name); mSearchTimelines.insert(name, mbw); timelines().insert(name, mbw); timelinesTabWidget()->addTab(mbw, name); QString textToAdd = name; if (textToAdd.contains(QLatin1Char(':'))) { QStringList splitted = textToAdd.split(QLatin1Char(':')); textToAdd = splitted.first().at(0) + QLatin1Char(':') + splitted[1].left(3); } else { textToAdd = textToAdd.left(4); } QIcon icon = addTextToIcon(QIcon::fromTheme(QLatin1String("edit-find")), textToAdd, QSize(40, 40), palette()); mbw->setTimelineIcon(icon); timelinesTabWidget()->setTabIcon(timelinesTabWidget()->indexOf(mbw), icon); - connect(mbw, SIGNAL(updateUnreadCount(int)), - this, SLOT(slotUpdateUnreadCount(int))); - connect(mbw, SIGNAL(closeMe()), this, SLOT(slotCloseCurrentSearch())); + connect(mbw, SIGNAL(updateUnreadCount(int)), this, SLOT(slotUpdateUnreadCount(int))); + connect(mbw, &TwitterApiSearchTimelineWidget::closeMe, this, &TwitterApiMicroBlogWidget::slotCloseCurrentSearch); if (composer()) { - connect(mbw, SIGNAL(forwardResendPost(QString)), - composer(), SLOT(setText(QString))); - connect(mbw, SIGNAL(forwardReply(QString,QString,QString)), - composer(), SLOT(setText(QString,QString,QString))); + connect(mbw, SIGNAL(forwardResendPost(QString)), composer(), SLOT(setText(QString))); + connect(mbw, &TwitterApiSearchTimelineWidget::forwardReply, composer(), &Choqok::UI::ComposerWidget::setText); } timelinesTabWidget()->setCurrentWidget(mbw); } else { qCDebug(CHOQOK) << "Cannot Create a new TimelineWidget for timeline " << name; return nullptr; } if (timelinesTabWidget()->count() == 1) { timelinesTabWidget()->setTabBarHidden(true); } else { timelinesTabWidget()->setTabBarHidden(false); } return mbw; } void TwitterApiMicroBlogWidget::slotCloseCurrentSearch() { Choqok::UI::TimelineWidget *stw = qobject_cast(sender()); if (!stw) { stw = qobject_cast(timelinesTabWidget()->currentWidget()); } closeSearch(stw); } void TwitterApiMicroBlogWidget::slotAccountModified(Choqok::Account *account) { for (const QString &timeline: account->microblog()->timelineNames()) { if (account->timelineNames().contains(timeline)) { if (!timelines().contains(timeline)) { addTimelineWidgetToUi(timeline); } } else if (timelines().contains(timeline)) { Choqok::UI::TimelineWidget *tm = timelines().take(timeline); tm->deleteLater(); } } } void TwitterApiMicroBlogWidget::saveSearchTimelinesState() { qCDebug(CHOQOK); int count = currentAccount()->configGroup()->readEntry("SearchCount", 0); int i = 0; while (i < count) { currentAccount()->configGroup()->deleteEntry(QLatin1String("Search") + QString::number(i)); ++i; } i = 0; for (TwitterApiSearchTimelineWidget *tm: mSearchTimelines.values()) { currentAccount()->configGroup()->writeEntry(QLatin1String("Search") + QString::number(i), tm->searchInfo().toString()); ++i; } currentAccount()->configGroup()->writeEntry("SearchCount", i); } void TwitterApiMicroBlogWidget::loadSearchTimelinesState() { qCDebug(CHOQOK); int count = currentAccount()->configGroup()->readEntry(QLatin1String("SearchCount"), 0); int i = 0; while (i < count) { SearchInfo info; if (info.fromString(currentAccount()->configGroup()->readEntry(QLatin1String("Search") + QString::number(i), QString()))) { qobject_cast(currentAccount()->microblog())->searchBackend()->requestSearchResults(info); } ++i; } } void TwitterApiMicroBlogWidget::slotContextMenu(QWidget *w, const QPoint &pt) { qCDebug(CHOQOK); Choqok::UI::TimelineWidget *sWidget = qobject_cast(w); QMenu menu; QAction *mar = 0; QAction *ac = 0; if (sWidget->unreadCount() > 0) { mar = new QAction(QIcon::fromTheme(QLatin1String("mail-mark-read")), i18n("Mark timeline as read"), &menu); menu.addAction(mar); } if (sWidget->isClosable()) { ac = new QAction(QIcon::fromTheme(QLatin1String("tab-close")), i18n("Close Timeline"), &menu); QAction *closeAll = new QAction(QIcon::fromTheme(QLatin1String("tab-close")), i18n("Close All"), &menu); - connect(closeAll, SIGNAL(triggered(bool)), this, SLOT(closeAllSearches())); + connect(closeAll, &QAction::triggered, this, &TwitterApiMicroBlogWidget::closeAllSearches); menu.addAction(ac); menu.addAction(closeAll); } QAction *res = menu.exec(pt); if (ac && res == ac) { closeSearch(sWidget); } else if (res == mar) { sWidget->markAllAsRead(); } } void TwitterApiMicroBlogWidget::closeSearch(Choqok::UI::TimelineWidget *searchWidget) { if (!searchWidget) { return; } searchWidget->markAllAsRead(); TwitterApiSearchTimelineWidget *tst = qobject_cast(searchWidget); timelinesTabWidget()->removePage(searchWidget); if (tst) { QString name = mSearchTimelines.key(tst); mSearchTimelines.value(name)->close(); mSearchTimelines.remove(name); timelines().remove(name); } else { QStringList lst = d->account->timelineNames(); lst.removeOne(searchWidget->timelineName()); d->account->setTimelineNames(lst); d->account->writeConfig(); timelines().remove(timelines().key(searchWidget)); searchWidget->close(); } } void TwitterApiMicroBlogWidget::closeAllSearches() { for (TwitterApiSearchTimelineWidget *searchWidget: mSearchTimelines.values()) { closeSearch(searchWidget); } for (Choqok::UI::TimelineWidget *widget: timelines().values()) { if (widget->isClosable()) { closeSearch(widget); } } } diff --git a/helperlibs/twitterapihelper/twitterapipostwidget.cpp b/helperlibs/twitterapihelper/twitterapipostwidget.cpp index 90b068a6..cf666ab8 100644 --- a/helperlibs/twitterapihelper/twitterapipostwidget.cpp +++ b/helperlibs/twitterapihelper/twitterapipostwidget.cpp @@ -1,320 +1,314 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapipostwidget.h" #include #include #include #include #include #include #include "choqokappearancesettings.h" #include "mediamanager.h" #include "microblog.h" #include "textbrowser.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" #include "twitterapishowthread.h" const QIcon TwitterApiPostWidget::unFavIcon(Choqok::MediaManager::convertToGrayScale(QIcon::fromTheme(QLatin1String("rating")).pixmap(16))); class TwitterApiPostWidget::Private { public: Private(Choqok::Account *account) : isBasePostShowed(false) { mBlog = qobject_cast(account->microblog()); } QPushButton *btnFav; bool isBasePostShowed; TwitterApiMicroBlog *mBlog; }; TwitterApiPostWidget::TwitterApiPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) : PostWidget(account, post, parent), d(new Private(account)) { mainWidget()->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://thread")), QIcon::fromTheme(QLatin1String("go-top")).pixmap(10)); } TwitterApiPostWidget::~TwitterApiPostWidget() { delete d; } void TwitterApiPostWidget::initUi() { Choqok::UI::PostWidget::initUi(); QPushButton *btnRe = addButton(QLatin1String("btnReply"), i18nc("@info:tooltip", "Reply"), QLatin1String("edit-undo")); - connect(btnRe, SIGNAL(clicked(bool)), SLOT(slotReply())); + connect(btnRe, &QPushButton::clicked, this, &TwitterApiPostWidget::slotReply); QMenu *menu = new QMenu(btnRe); btnRe->setMenu(menu); QAction *actRep = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18n("Reply to %1", currentPost()->author.userName), menu); menu->addAction(actRep); menu->setDefaultAction(actRep); - connect(actRep, SIGNAL(triggered(bool)), SLOT(slotReply())); + connect(actRep, &QAction::triggered, this, &TwitterApiPostWidget::slotReply); QAction *actWrite = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Write to %1", currentPost()->author.userName), menu); menu->addAction(actWrite); - connect(actWrite, SIGNAL(triggered(bool)), SLOT(slotWriteTo())); + connect(actWrite, &QAction::triggered, this, &TwitterApiPostWidget::slotWriteTo); if (!currentPost()->isPrivate) { QAction *actReplytoAll = new QAction(i18n("Reply to all"), menu); menu->addAction(actReplytoAll); - connect(actReplytoAll, SIGNAL(triggered(bool)), SLOT(slotReplyToAll())); + connect(actReplytoAll, &QAction::triggered, this, &TwitterApiPostWidget::slotReplyToAll); d->btnFav = addButton(QLatin1String("btnFavorite"), i18nc("@info:tooltip", "Favorite"), QLatin1String("rating")); d->btnFav->setCheckable(true); - connect(d->btnFav, SIGNAL(clicked(bool)), SLOT(setFavorite())); + connect(d->btnFav, &QPushButton::clicked, this, &TwitterApiPostWidget::setFavorite); updateFavStat(); } } QString TwitterApiPostWidget::generateSign() { QString sign = QStringLiteral("%1 - ").arg(getUsernameHyperlink(currentPost()->author)); // if (currentPost()->isPrivate) { sign += QLatin1String("%1"); if (currentPost()->replyToUser.userName.compare(currentAccount()->username(), Qt::CaseInsensitive) == 0) { sign.prepend(QLatin1String("From ")); } else { sign.prepend(QLatin1String("To ")); } } else { QDateTime time; if (currentPost()->repeatedDateTime.isNull()) { time = currentPost()->creationDateTime; } else { time = currentPost()->repeatedDateTime; } sign += QStringLiteral("%3").arg(currentPost()->link.toDisplayString()) .arg(time.toString(Qt::DefaultLocaleLongDate)).arg(formatDateTime(time)); } if (!currentPost()->source.isEmpty()) { sign += QLatin1String(" - "); if (currentPost()->source == QLatin1String("ostatus") && !currentPost()->author.homePageUrl.isEmpty()) { sign += i18n("%2", currentPost()->author.homePageUrl.toDisplayString(), currentPost()->author.homePageUrl.host()); } else { sign += currentPost()->source; } } if (!currentPost()->isPrivate) { if (!currentPost()->replyToPostId.isEmpty()) { QUrl link = currentAccount()->microblog()->postUrl(currentAccount(), currentPost()->replyToUser.userName, currentPost()->replyToPostId); QString showConMsg = i18n("Show Conversation"); QString threadlink; if (currentPost()->conversationId.isEmpty()) { threadlink = QLatin1String("thread://") + currentPost()->postId; } else { threadlink = QLatin1String("conversation://") + currentPost()->conversationId; } sign += QLatin1String(" - ") + i18n("in reply to @%4 %3", currentPost()->replyToPostId, link.toDisplayString(), webIconText, currentPost()->replyToUser.userName) + QLatin1Char(' '); sign += QLatin1String(""); } //ReTweet detection if (!currentPost()->repeatedFromUser.userName.isEmpty()) { const QString retweet = QLatin1String("
") + d->mBlog->generateRepeatedByUserTooltip(QStringLiteral("%2") .arg(currentPost()->repeatedFromUser.userName) .arg(currentPost()->repeatedFromUser.userName)); sign.append(retweet); } } sign.prepend(QLatin1String("

")); sign.append(QLatin1String("

")); return sign; } QString TwitterApiPostWidget::getUsernameHyperlink(const Choqok::User &user) const { return QStringLiteral("%3") .arg(user.userName) .arg(user.description.isEmpty() ? user.realName : user.description.toHtmlEscaped()) .arg(user.userName); } void TwitterApiPostWidget::slotReply() { setReadWithSignal(); if (currentPost()->isPrivate) { TwitterApiAccount *account = qobject_cast(currentAccount()); d->mBlog->showDirectMessageDialog(account, currentPost()->author.userName); } else { QString replyto = QStringLiteral("@%1").arg(currentPost()->author.userName); QString postId = currentPost()->postId; QString username = currentPost()->author.userName; if (!currentPost()->repeatedFromUser.userName.isEmpty()) { replyto.prepend(QStringLiteral("@%1 ").arg(currentPost()->repeatedFromUser.userName)); postId = currentPost()->repeatedPostId; } Q_EMIT reply(replyto, postId, username); } } void TwitterApiPostWidget::slotWriteTo() { Q_EMIT reply(QStringLiteral("@%1").arg(currentPost()->author.userName), QString(), currentPost()->author.userName); } void TwitterApiPostWidget::slotReplyToAll() { QString txt = QStringLiteral("@%1").arg(currentPost()->author.userName); Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName); } void TwitterApiPostWidget::setFavorite() { setReadWithSignal(); TwitterApiMicroBlog *mic = d->mBlog; if (currentPost()->isFavorited) { - connect(mic, SIGNAL(favoriteRemoved(Choqok::Account*,QString)), - this, SLOT(slotSetFavorite(Choqok::Account*,QString))); + connect(mic, &TwitterApiMicroBlog::favoriteRemoved, this, &TwitterApiPostWidget::slotSetFavorite); mic->removeFavorite(currentAccount(), currentPost()->postId); } else { - connect(mic, SIGNAL(favoriteCreated(Choqok::Account*,QString)), - this, SLOT(slotSetFavorite(Choqok::Account*,QString))); + connect(mic, &TwitterApiMicroBlog::favoriteCreated, this, &TwitterApiPostWidget::slotSetFavorite); mic->createFavorite(currentAccount(), currentPost()->postId); } } void TwitterApiPostWidget::slotSetFavorite(Choqok::Account *theAccount, const QString &postId) { if (currentAccount() == theAccount && postId == currentPost()->postId) { qCDebug(CHOQOK) << postId; currentPost()->isFavorited = !currentPost()->isFavorited; updateFavStat(); - disconnect(d->mBlog, SIGNAL(favoriteRemoved(Choqok::Account*,QString)), - this, SLOT(slotSetFavorite(Choqok::Account*,QString))); - disconnect(d->mBlog, SIGNAL(favoriteCreated(Choqok::Account*,QString)), - this, SLOT(slotSetFavorite(Choqok::Account*,QString))); + disconnect(d->mBlog, &TwitterApiMicroBlog::favoriteRemoved, this, &TwitterApiPostWidget::slotSetFavorite); + disconnect(d->mBlog, &TwitterApiMicroBlog::favoriteCreated, this, &TwitterApiPostWidget::slotSetFavorite); } } void TwitterApiPostWidget::updateFavStat() { if (currentPost()->isFavorited) { d->btnFav->setChecked(true); d->btnFav->setIcon(QIcon::fromTheme(QLatin1String("rating"))); } else { d->btnFav->setChecked(false); d->btnFav->setIcon(unFavIcon); } } void TwitterApiPostWidget::checkAnchor(const QUrl &url) { QString scheme = url.scheme(); if (scheme == QLatin1String("replyto")) { if (d->isBasePostShowed) { setContent(prepareStatus(currentPost()->content).replace(QLatin1String("isBasePostShowed = false; return; } else { - connect(currentAccount()->microblog(), SIGNAL(postFetched(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotBasePostFetched(Choqok::Account*,Choqok::Post*))); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::postFetched, + this, &TwitterApiPostWidget::slotBasePostFetched); Choqok::Post *ps = new Choqok::Post; ps->postId = url.host(); currentAccount()->microblog()->fetchPost(currentAccount(), ps); } } else if (scheme == QLatin1String("thread")) { TwitterApiShowThread *wd = new TwitterApiShowThread(currentAccount(), currentPost(), nullptr); wd->resize(this->width(), wd->height()); - connect(wd, SIGNAL(forwardReply(QString,QString,QString)), - this, SIGNAL(reply(QString,QString,QString))); - connect(wd, SIGNAL(forwardResendPost(QString)), - this, SIGNAL(resendPost(QString))); + connect(wd, &TwitterApiShowThread::forwardReply, this, &TwitterApiPostWidget::reply); + connect(wd, &TwitterApiShowThread::forwardResendPost, this, &TwitterApiPostWidget::resendPost); wd->show(); } else { Choqok::UI::PostWidget::checkAnchor(url); } } void TwitterApiPostWidget::slotBasePostFetched(Choqok::Account *theAccount, Choqok::Post *post) { if (theAccount == currentAccount() && post && post->postId == currentPost()->replyToPostId) { qCDebug(CHOQOK); - disconnect(currentAccount()->microblog(), SIGNAL(postFetched(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotBasePostFetched(Choqok::Account*,Choqok::Post*))); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postFetched, + this, &TwitterApiPostWidget::slotBasePostFetched); if (d->isBasePostShowed) { return; } d->isBasePostShowed = true; QString color; if (Choqok::AppearanceSettings::isCustomUi()) { color = Choqok::AppearanceSettings::readForeColor().lighter().name(); } else { color = this->palette().dark().color().name(); } QString baseStatusText = QLatin1String("

"); baseStatusText += QLatin1String("") + post->author.userName + QLatin1String(" : "); baseStatusText += prepareStatus(post->content) + QLatin1String("

"); setContent(content().prepend(baseStatusText.replace(QLatin1String("owners < 1 ) delete post; } } void TwitterApiPostWidget::repeatPost() { setReadWithSignal(); QString postId; if (currentPost()->repeatedPostId.isEmpty()) { postId = currentPost()->postId; } else { postId = currentPost()->repeatedPostId; } auto q_answer = KMessageBox::questionYesNo(Choqok::UI::Global::mainWindow(), d->mBlog->repeatQuestion(), QString(), KStandardGuiItem::yes(), KStandardGuiItem::cancel(), QLatin1String("dontAskRepeatConfirm")); if ( q_answer == KMessageBox::Yes) { d->mBlog->repeatPost(currentAccount(), postId); } } diff --git a/helperlibs/twitterapihelper/twitterapisearchdialog.cpp b/helperlibs/twitterapihelper/twitterapisearchdialog.cpp index e6ced56a..c0e8d3fa 100644 --- a/helperlibs/twitterapihelper/twitterapisearchdialog.cpp +++ b/helperlibs/twitterapihelper/twitterapisearchdialog.cpp @@ -1,132 +1,133 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapisearchdialog.h" #include #include #include #include #include #include #include #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" #include "twitterapisearch.h" class TwitterApiSearchDialog::Private { public: Private(TwitterApiAccount *theAccount) : account(theAccount) { qCDebug(CHOQOK); mBlog = qobject_cast(account->microblog()); if (!mBlog) { qCCritical(CHOQOK) << "microblog is not a TwitterApiMicroBlog"; } Q_ASSERT(mBlog); } QComboBox *searchTypes; QLineEdit *searchQuery; TwitterApiAccount *account; TwitterApiMicroBlog *mBlog; }; TwitterApiSearchDialog::TwitterApiSearchDialog(TwitterApiAccount *theAccount, QWidget *parent) : QDialog(parent), d(new Private(theAccount)) { qCDebug(CHOQOK); setWindowTitle(i18nc("@title:window", "Search")); setAttribute(Qt::WA_DeleteOnClose); createUi(); d->searchQuery->setFocus(); - connect(d->searchTypes, SIGNAL(currentIndexChanged(int)), SLOT(slotSearchTypeChanged(int))); + connect(d->searchTypes, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, this, + &TwitterApiSearchDialog::slotSearchTypeChanged); } TwitterApiSearchDialog::~TwitterApiSearchDialog() { delete d; } void TwitterApiSearchDialog::createUi() { qCDebug(CHOQOK); QWidget *wd = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout; setLayout(layout); layout->addWidget(wd); d->searchTypes = new QComboBox(wd); fillSearchTypes(); qCDebug(CHOQOK); layout->addWidget(d->searchTypes); QHBoxLayout *queryLayout = new QHBoxLayout; layout->addLayout(queryLayout); QLabel *lblType = new QLabel(i18nc("Search query", "Query:"), wd); lblType->setAlignment(Qt::AlignRight | Qt::AlignVCenter); queryLayout->addWidget(lblType); d->searchQuery = new QLineEdit(this); queryLayout->addWidget(d->searchQuery); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); okButton->setText(i18nc("@action:button", "Search")); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &TwitterApiSearchDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &TwitterApiSearchDialog::reject); layout->addWidget(buttonBox); adjustSize(); } void TwitterApiSearchDialog::fillSearchTypes() { qCDebug(CHOQOK); QMap > searchTypes = d->mBlog->searchBackend()->getSearchTypes(); int count = searchTypes.count(); for (int i = 0; i < count; ++i) { d->searchTypes->insertItem(i, searchTypes[i].first); } } void TwitterApiSearchDialog::accept() { bool isB = d->mBlog->searchBackend()->getSearchTypes()[d->searchTypes->currentIndex()].second; SearchInfo info(d->account, d->searchQuery->text(), d->searchTypes->currentIndex(), isB); d->mBlog->searchBackend()->requestSearchResults(info); QDialog::accept(); } void TwitterApiSearchDialog::slotSearchTypeChanged(int) { d->searchQuery->setFocus(); } diff --git a/helperlibs/twitterapihelper/twitterapisearchtimelinewidget.cpp b/helperlibs/twitterapihelper/twitterapisearchtimelinewidget.cpp index 25ab3f18..34d99e13 100644 --- a/helperlibs/twitterapihelper/twitterapisearchtimelinewidget.cpp +++ b/helperlibs/twitterapihelper/twitterapisearchtimelinewidget.cpp @@ -1,212 +1,212 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapisearchtimelinewidget.h" #include #include #include #include #include #include #include #include #include #include "account.h" #include "choqokbehaviorsettings.h" #include "choqoktypes.h" #include "postwidget.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" class TwitterApiSearchTimelineWidget::Private { public: Private(const SearchInfo &info) : currentPage(1), searchInfo(info), loadingAnotherPage(false) {} QPointer close; QPointer next; QPointer previous; QPointer pageNumber; QPointer autoUpdate; uint currentPage; SearchInfo searchInfo; QPointer searchBackend; bool loadingAnotherPage; }; TwitterApiSearchTimelineWidget::TwitterApiSearchTimelineWidget(Choqok::Account *account, const QString &timelineName, const SearchInfo &info, QWidget *parent) : TimelineWidget(account, timelineName, parent), d(new Private(info)) { setAttribute(Qt::WA_DeleteOnClose); d->searchBackend = qobject_cast(currentAccount()->microblog())->searchBackend(); - connect(Choqok::UI::Global::mainWindow(), SIGNAL(updateTimelines()), - this, SLOT(slotUpdateSearchResults())); + connect(Choqok::UI::Global::mainWindow(), &Choqok::UI::MainWindow::updateTimelines, + this, &TwitterApiSearchTimelineWidget::slotUpdateSearchResults); addFooter(); timelineDescription()->setText(i18nc("%1 is the name of a timeline", "Search results for %1", timelineName)); setClosable(); } TwitterApiSearchTimelineWidget::~TwitterApiSearchTimelineWidget() { delete d; } void TwitterApiSearchTimelineWidget::saveTimeline() { qCDebug(CHOQOK); //There's no implementation because we don't want to have it in Search Timelines :) // Choqok::UI::TimelineWidget::saveTimeline(); } void TwitterApiSearchTimelineWidget::loadTimeline() { qCDebug(CHOQOK); //There's no implementation because we don't want to have it in Search Timelines :) // Choqok::UI::TimelineWidget::loadTimeline(); } void TwitterApiSearchTimelineWidget::addFooter() { QHBoxLayout *footer = titleBarLayout(); d->close = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-close")), QString(), this); d->close->setFixedSize(28, 28); d->close->setToolTip(i18n("Close Search")); if (d->searchInfo.isBrowsable) { d->previous = new QPushButton(this); d->previous->setIcon(QIcon::fromTheme(QLatin1String("go-previous"))); d->previous->setMaximumSize(28, 28); d->previous->setToolTip(i18n("Previous")); d->next = new QPushButton(this); d->next->setIcon(QIcon::fromTheme(QLatin1String("go-next"))); d->next->setMaximumSize(28, 28); d->next->setToolTip(i18n("Next")); d->pageNumber = new QLineEdit(this); d->pageNumber->setValidator(new QIntValidator); d->pageNumber->setMaxLength(2); d->pageNumber->setMaximumWidth(40); d->pageNumber->setAlignment(Qt::AlignCenter); d->pageNumber->setToolTip(i18n("Page Number")); footer->addWidget(d->previous); footer->addWidget(d->pageNumber); footer->addWidget(d->next); footer->addWidget(new KSeparator(Qt::Vertical, this)); - connect(d->next, SIGNAL(clicked(bool)), SLOT(loadNextPage())); - connect(d->previous, SIGNAL(clicked(bool)), SLOT(loadPreviousPage())); - connect(d->pageNumber, SIGNAL(returnPressed()), SLOT(loadCustomPage())); + connect(d->next, &QPushButton::clicked, this, &TwitterApiSearchTimelineWidget::loadNextPage); + connect(d->previous, &QPushButton::clicked, this, &TwitterApiSearchTimelineWidget::loadPreviousPage); + connect(d->pageNumber, &QLineEdit::returnPressed, this, + (void (TwitterApiSearchTimelineWidget::*)())&TwitterApiSearchTimelineWidget::loadCustomPage); } footer->addWidget(d->close); - connect(d->close, SIGNAL(clicked(bool)), this, SIGNAL(closeMe())); - + connect(d->close, &QPushButton::clicked, this, &TwitterApiSearchTimelineWidget::closeMe); } void TwitterApiSearchTimelineWidget::addNewPosts(QList< Choqok::Post * > &postList) { if (d->loadingAnotherPage) { removeAllPosts(); d->loadingAnotherPage = false; } /*bool markRead = false; if( posts().count() < 1 ) markRead = true;*/ int m = postList.count() - Choqok::BehaviorSettings::countOfPosts(); // qCDebug(CHOQOK)< 0) { postList.removeFirst(); --m; } Choqok::UI::TimelineWidget::addNewPosts(postList); // if(markRead) // markAllAsRead(); if (d->pageNumber) { d->pageNumber->setText(QString::number(d->currentPage)); } } void TwitterApiSearchTimelineWidget::reloadList() { loadCustomPage(QString::number(d->currentPage)); } void TwitterApiSearchTimelineWidget::loadCustomPage() { loadCustomPage(d->pageNumber->text()); } void TwitterApiSearchTimelineWidget::loadCustomPage(const QString &pageNumber) { int page = pageNumber.toUInt(); if (page == 0) { page = 1; } d->loadingAnotherPage = true; d->currentPage = page; d->searchBackend->requestSearchResults(d->searchInfo, QString(), 0, page); } void TwitterApiSearchTimelineWidget::loadNextPage() { loadCustomPage(QString::number(++d->currentPage)); } void TwitterApiSearchTimelineWidget::loadPreviousPage() { loadCustomPage(QString::number(--d->currentPage)); } void TwitterApiSearchTimelineWidget::removeAllPosts() { for (Choqok::UI::PostWidget *wd: posts().values()) { wd->close(); } posts().clear(); } void TwitterApiSearchTimelineWidget::slotUpdateSearchResults() { if (d->currentPage == 1) { QString lastId; if (!postWidgets().isEmpty()) { lastId = postWidgets().last()->currentPost()->postId; } d->searchBackend->requestSearchResults(d->searchInfo, lastId); } } SearchInfo TwitterApiSearchTimelineWidget::searchInfo() const { return d->searchInfo; } diff --git a/helperlibs/twitterapihelper/twitterapishowthread.cpp b/helperlibs/twitterapihelper/twitterapishowthread.cpp index 034bf16b..4a497c6c 100644 --- a/helperlibs/twitterapihelper/twitterapishowthread.cpp +++ b/helperlibs/twitterapihelper/twitterapishowthread.cpp @@ -1,145 +1,140 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapishowthread.h" #include #include #include #include "postwidget.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" class TwitterApiShowThread::Private { public: Private(Choqok::Account *currentAccount) : account(currentAccount) {} QVBoxLayout *mainLayout; Choqok::Account *account; QString desiredPostId; }; TwitterApiShowThread::TwitterApiShowThread(Choqok::Account *account, Choqok::Post *finalPost, QWidget *parent) : QWidget(parent), d(new Private(account)) { qCDebug(CHOQOK); setupUi(); setWindowTitle(i18n("Conversation")); - connect(account->microblog(), SIGNAL(postFetched(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotAddNewPost(Choqok::Account*,Choqok::Post*))); + connect(account->microblog(), &Choqok::MicroBlog::postFetched, this, &TwitterApiShowThread::slotAddNewPost); Choqok::UI::PostWidget *widget = d->account->microblog()->createPostWidget(d->account, finalPost, this); if (widget) { addPostWidgetToUi(widget); Choqok::Post *ps = new Choqok::Post; ps->postId = finalPost->replyToPostId; d->desiredPostId = finalPost->replyToPostId; d->account->microblog()->fetchPost(d->account, ps); } } TwitterApiShowThread::~TwitterApiShowThread() { delete d; } void TwitterApiShowThread::setupUi() { qCDebug(CHOQOK); QVBoxLayout *gridLayout; QScrollArea *scrollArea; QWidget *scrollAreaWidgetContents; QVBoxLayout *verticalLayout_2; QSpacerItem *verticalSpacer; gridLayout = new QVBoxLayout(this); gridLayout->setMargin(0); gridLayout->setObjectName(QLatin1String("gridLayout")); scrollArea = new QScrollArea(this); scrollArea->setObjectName(QLatin1String("scrollArea")); scrollArea->setFrameShape(QFrame::NoFrame); scrollArea->setWidgetResizable(true); scrollAreaWidgetContents = new QWidget(); scrollAreaWidgetContents->setObjectName(QLatin1String("scrollAreaWidgetContents")); scrollAreaWidgetContents->setGeometry(QRect(0, 0, 254, 300)); verticalLayout_2 = new QVBoxLayout(scrollAreaWidgetContents); verticalLayout_2->setMargin(1); d->mainLayout = new QVBoxLayout(); verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); d->mainLayout->addItem(verticalSpacer); d->mainLayout->setSpacing(3); d->mainLayout->setMargin(1); verticalLayout_2->addLayout(d->mainLayout); scrollArea->setWidget(scrollAreaWidgetContents); gridLayout->addWidget(scrollArea); } void TwitterApiShowThread::slotAddNewPost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (theAccount == d->account && post->postId == d->desiredPostId) { Choqok::UI::PostWidget *widget = d->account->microblog()->createPostWidget(d->account, post, this); if (widget) { addPostWidgetToUi(widget); Choqok::Post *ps = new Choqok::Post; ps->postId = post->replyToPostId; d->desiredPostId = ps->postId; d->account->microblog()->fetchPost(d->account, ps); } } } void TwitterApiShowThread::addPostWidgetToUi(Choqok::UI::PostWidget *widget) { qCDebug(CHOQOK); widget->initUi(); widget->setRead(); widget->setFocusProxy(this); widget->setObjectName(widget->currentPost()->postId); - connect(widget, SIGNAL(resendPost(QString)), - this, SIGNAL(forwardResendPost(QString))); - connect(widget, SIGNAL(resendPost(QString)), - this, SLOT(raiseMainWindow())); - connect(widget, SIGNAL(reply(QString,QString)), - this, SLOT(raiseMainWindow())); - connect(widget, SIGNAL(reply(QString,QString,QString)), - this, SIGNAL(forwardReply(QString,QString,QString))); + connect(widget, &Choqok::UI::PostWidget::resendPost, this, &TwitterApiShowThread::forwardResendPost); + connect(widget, &Choqok::UI::PostWidget::resendPost, this, &TwitterApiShowThread::raiseMainWindow); + connect(widget, &Choqok::UI::PostWidget::reply, this, &TwitterApiShowThread::raiseMainWindow); + connect(widget, &Choqok::UI::PostWidget::reply, this, &TwitterApiShowThread::forwardReply); // connect( widget, SIGNAL(aboutClosing(QString,PostWidget*)), // SLOT(postWidgetClosed(QString,PostWidget*)) ); d->mainLayout->insertWidget(0, widget); // d->posts.insert(widget->currentPost().postId, widget); Choqok::UI::Global::SessionManager::self()->emitNewPostWidgetAdded(widget, d->account); } void TwitterApiShowThread::raiseMainWindow() { Choqok::UI::Global::mainWindow()->activateWindow(); } diff --git a/helperlibs/twitterapihelper/twitterapitextedit.cpp b/helperlibs/twitterapihelper/twitterapitextedit.cpp index 560d6763..2b7eb9b5 100644 --- a/helperlibs/twitterapihelper/twitterapitextedit.cpp +++ b/helperlibs/twitterapihelper/twitterapitextedit.cpp @@ -1,183 +1,183 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapitextedit.h" #include #include #include #include #include "urlutils.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" class TwitterApiTextEdit::Private { public: Private(Choqok::Account *theAccount) : acc(theAccount), c(0) {} Choqok::Account *acc; QCompleter *c; }; TwitterApiTextEdit::TwitterApiTextEdit(Choqok::Account *theAccount, QWidget *parent) : TextEdit(theAccount->postCharLimit(), parent), d(new Private(theAccount)) { qCDebug(CHOQOK); setTabChangesFocus(false); } TwitterApiTextEdit::~TwitterApiTextEdit() { delete d; } void TwitterApiTextEdit::setCompleter(QCompleter *completer) { if (d->c) { QObject::disconnect(d->c, 0, this, 0); } d->c = completer; if (!d->c) { return; } d->c->setWidget(this); d->c->setCompletionMode(QCompleter::PopupCompletion); d->c->setCaseSensitivity(Qt::CaseInsensitive); - QObject::connect(d->c, SIGNAL(activated(QString)), - this, SLOT(insertCompletion(QString))); + connect(d->c, (void (QCompleter::*)(const QString&))&QCompleter::activated, + this, &TwitterApiTextEdit::insertCompletion); } QCompleter *TwitterApiTextEdit::completer() const { return d->c; } void TwitterApiTextEdit::insertCompletion(const QString &completion) { if (d->c->widget() != this) { return; } QString textToInsert = completion + QLatin1Char(' '); QTextCursor tc = textCursor(); tc.movePosition(QTextCursor::EndOfWord); tc.select(QTextCursor::WordUnderCursor); bool startWithAt = toPlainText()[tc.selectionStart() - 1] != QLatin1Char('@'); if (startWithAt) { textToInsert.prepend(QLatin1Char('@')); } tc.insertText(textToInsert); setTextCursor(tc); } // QString TwitterApiTextEdit::textUnderCursor() const // { // QTextCursor tc = textCursor(); // tc.select(QTextCursor::WordUnderCursor); // return tc.selectedText(); // } void TwitterApiTextEdit::focusInEvent(QFocusEvent *e) { if (d->c) { d->c->setWidget(this); } KTextEdit::focusInEvent(e); } void TwitterApiTextEdit::keyPressEvent(QKeyEvent *e) { if (d->c && d->c->popup()->isVisible()) { // The following keys are forwarded by the completer to the widget switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Escape: // case Qt::Key_Backtab: e->ignore(); return; // let the completer do default behavior default: // Choqok::UI::TextEdit::keyPressEvent(e); break; } } else if (e->text().isEmpty()) { Choqok::UI::TextEdit::keyPressEvent(e); return; } if (e->key() == Qt::Key_Tab) { e->ignore(); return; } // bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_Space); // CTRL+E // if (!d->c )// || !isShortcut) // don't process the shortcut when we have a completer Choqok::UI::TextEdit::keyPressEvent(e); const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier | Qt::AltModifier | Qt::MetaModifier); if (!d->c || (ctrlOrShift && e->text().isEmpty())) { return; } static QString eow(QLatin1String("~!@#$%^&*()+{}|:\"<>?,./;'[]\\-= ")); // end of word // bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift; //Implemented internally to get the char before selection :D QTextCursor tc = textCursor(); tc.select(QTextCursor::WordUnderCursor); QString completionPrefix = tc.selectedText(); QChar charBeforeSelection; if (completionPrefix.startsWith(QLatin1Char('@'))) { charBeforeSelection = completionPrefix.at(0); completionPrefix.remove(0, 1); } else { if (!toPlainText().isEmpty() && tc.selectionStart() > 0) { charBeforeSelection = toPlainText()[tc.selectionStart() - 1]; } } if (!e->text().isEmpty() && (eow.contains(e->text().right(1)) || completionPrefix.length() < 1 || charBeforeSelection != QLatin1Char('@'))) { d->c->popup()->hide(); return; } else if ((e->key() != Qt::Key_Enter) && (e->key() != Qt::Key_Return)) { if (textCursor().selectedText().length() && textCursor().selectedText() != completionPrefix) { return; } if (completionPrefix != d->c->completionPrefix()) { d->c->setCompletionPrefix(completionPrefix); d->c->popup()->setCurrentIndex(d->c->completionModel()->index(0, 0)); } QRect cr = cursorRect(); cr.setWidth(d->c->popup()->sizeHintForColumn(0) + d->c->popup()->verticalScrollBar()->sizeHint().width()); d->c->complete(cr); // popup it up! } } diff --git a/helperlibs/twitterapihelper/twitterapitimelinewidget.cpp b/helperlibs/twitterapihelper/twitterapitimelinewidget.cpp index 5c284c74..ab0283d7 100644 --- a/helperlibs/twitterapihelper/twitterapitimelinewidget.cpp +++ b/helperlibs/twitterapihelper/twitterapitimelinewidget.cpp @@ -1,52 +1,52 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapitimelinewidget.h" #include "twitterapimicroblog.h" #include "postwidget.h" TwitterApiTimelineWidget::TwitterApiTimelineWidget(Choqok::Account *account, const QString &timelineName, QWidget *parent) : TimelineWidget(account, timelineName, parent) { if (timelineName == QLatin1String("Favorite")) { TwitterApiMicroBlog *mBlog = qobject_cast(account->microblog()); - connect(mBlog, SIGNAL(favoriteRemoved(Choqok::Account*,QString)), - this, SLOT(removeUnFavoritedPost(Choqok::Account*,QString))); + connect(mBlog, &TwitterApiMicroBlog::favoriteRemoved, this, + &TwitterApiTimelineWidget::removeUnFavoritedPost); } } TwitterApiTimelineWidget::~TwitterApiTimelineWidget() { } void TwitterApiTimelineWidget::removeUnFavoritedPost(Choqok::Account *theAccount, const QString &postId) { if (theAccount == currentAccount()) { if (posts().contains(postId)) { posts().value(postId)->close(); } } } diff --git a/helperlibs/twitterapihelper/twitterapiwhoiswidget.cpp b/helperlibs/twitterapihelper/twitterapiwhoiswidget.cpp index 92ed4d01..565bfb54 100644 --- a/helperlibs/twitterapihelper/twitterapiwhoiswidget.cpp +++ b/helperlibs/twitterapihelper/twitterapiwhoiswidget.cpp @@ -1,426 +1,426 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterapiwhoiswidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "choqokappearancesettings.h" #include "choqoktools.h" #include "choqoktypes.h" #include "mediamanager.h" #include "microblog.h" #include "notifymanager.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" class TwitterApiWhoisWidget::Private { public: Private(TwitterApiAccount *account, const QString &userN) : currentAccount(account), waitFrame(0), job(0), username(userN) { mBlog = qobject_cast(account->microblog()); } QTextBrowser *wid; TwitterApiAccount *currentAccount; TwitterApiMicroBlog *mBlog; QFrame *waitFrame; QPointer job; Choqok::Post currentPost; QString username; QString errorMessage; QString followersCount; QString friendsCount; QString statusesCount; QString timeZone; QString imgActions; // bool isFollowing; }; TwitterApiWhoisWidget::TwitterApiWhoisWidget(TwitterApiAccount *theAccount, const QString &username, const Choqok::Post &post, QWidget *parent) : QFrame(parent), d(new Private(theAccount, username)) { qCDebug(CHOQOK); setAttribute(Qt::WA_DeleteOnClose); d->currentPost = post; loadUserInfo(theAccount, username); d->wid = new QTextBrowser(this); setFrameShape(StyledPanel); setFrameShadow(Sunken); d->wid->setFrameShape(QFrame::NoFrame); QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(d->wid); this->setLayout(layout); this->setWindowFlags(Qt::Popup);// | Qt::FramelessWindowHint | Qt::Ta); d->wid->setOpenLinks(false); - connect(d->wid, SIGNAL(anchorClicked(QUrl)), this, SLOT(checkAnchor(QUrl))); + connect(d->wid, &QTextBrowser::anchorClicked, this, &TwitterApiWhoisWidget::checkAnchor); setupUi(); setActionImages(); } TwitterApiWhoisWidget::~TwitterApiWhoisWidget() { qCDebug(CHOQOK); delete d; } void TwitterApiWhoisWidget::loadUserInfo(TwitterApiAccount *theAccount, const QString &username) { qCDebug(CHOQOK); QString urlStr; QString user = username; if (user.contains(QLatin1Char('@'))) { QStringList lst = user.split(QLatin1Char('@')); if (lst.count() == 2) { //USER@HOST QString host = lst[1]; urlStr = QStringLiteral("https://%1/api").arg(host); user = lst[0]; } } else if (d->currentPost.source == QLatin1String("ostatus") && !d->currentPost.author.homePageUrl.isEmpty()) { urlStr = d->currentPost.author.homePageUrl.toDisplayString(); if (urlStr.endsWith(user)) { int len = urlStr.length(); int userLen = user.length(); urlStr.remove(len - userLen, userLen); qCDebug(CHOQOK) << urlStr; } urlStr.append(QLatin1String("api")); } else { urlStr = theAccount->apiUrl().url(); } QUrl url(urlStr); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/users/show/%1.json").arg(user)); // qCDebug(CHOQOK) << url; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (d->currentPost.source != QLatin1String("ostatus")) { job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(d->mBlog->authorizationHeader(theAccount, url, QNetworkAccessManager::GetOperation))); } d->job = job; - connect(job, SIGNAL(result(KJob*)), SLOT(userInfoReceived(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterApiWhoisWidget::userInfoReceived); job->start(); } void TwitterApiWhoisWidget::userInfoReceived(KJob *job) { qCDebug(CHOQOK); if (job->error()) { qCCritical(CHOQOK) << "Job Error:" << job->errorString(); if (Choqok::UI::Global::mainWindow()->statusBar()) { Choqok::UI::Global::mainWindow()->statusBar()->showMessage(job->errorString()); } slotCancel(); return; } KIO::StoredTransferJob *stj = qobject_cast(job); // qCDebug(CHOQOK)<data(); const QJsonDocument json = QJsonDocument::fromJson(stj->data()); if (json.isNull()) { qCDebug(CHOQOK) << "JSON parsing failed! Data is:\n\t" << stj->data(); d->errorMessage = i18n("Cannot load user information."); updateHtml(); showForm(); return; } const QVariantMap map = json.toVariant().toMap(); QString timeStr; Choqok::Post post; d->errorMessage = map[QLatin1String("error")].toString(); if (d->errorMessage.isEmpty()) { //No Error post.author.realName = map[QLatin1String("name")].toString(); post.author.userName = map[QLatin1String("screen_name")].toString(); post.author.location = map[QLatin1String("location")].toString(); post.author.description = map[QLatin1String("description")].toString(); post.author.profileImageUrl = map[QLatin1String("profile_image_url")].toUrl(); post.author.homePageUrl = map[QLatin1String("url")].toUrl(); d->timeZone = map[QLatin1String("time_zone")].toString(); d->followersCount = map[QLatin1String("followers_count")].toString(); d->friendsCount = map[QLatin1String("friends_count")].toString(); d->statusesCount = map[QLatin1String("statuses_count")].toString(); QVariantMap var = map[QLatin1String("status")].toMap(); post.content = var[QLatin1String("text")].toString(); post.creationDateTime = d->mBlog->dateFromString(var[QLatin1String("created_at")].toString()); post.isFavorited = var[QLatin1String("favorited")].toBool(); post.postId = var[QLatin1String("id")].toString(); post.replyToPostId = var[QLatin1String("in_reply_to_status_id")].toString(); post.replyToUser.userId = var[QLatin1String("in_reply_to_user_id")].toString(); post.replyToUser.userName = var[QLatin1String("in_reply_to_screen_name")].toString(); post.source = var[QLatin1String("source")].toString(); d->currentPost = post; } updateHtml(); showForm(); QPixmap userAvatar = Choqok::MediaManager::self()->fetchImage(post.author.profileImageUrl, Choqok::MediaManager::Async); if (!userAvatar.isNull()) { d->wid->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("img://profileImage")), userAvatar); } else { - connect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(avatarFetched(QUrl,QPixmap))); - connect(Choqok::MediaManager::self(), SIGNAL(fetchError(QString,QString)), - this, SLOT(avatarFetchError(QString,QString))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &TwitterApiWhoisWidget::avatarFetched); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::fetchError, + this, &TwitterApiWhoisWidget::avatarFetchError); } } void TwitterApiWhoisWidget::avatarFetched(const QUrl &remoteUrl, const QPixmap &pixmap) { qCDebug(CHOQOK); if (remoteUrl == d->currentPost.author.profileImageUrl) { const QUrl url(QLatin1String("img://profileImage")); d->wid->document()->addResource(QTextDocument::ImageResource, url, pixmap); updateHtml(); - disconnect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(avatarFetched(QUrl,QPixmap))); - disconnect(Choqok::MediaManager::self(), SIGNAL(fetchError(QString,QString)), - this, SLOT(avatarFetchError(QString,QString))); + disconnect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &TwitterApiWhoisWidget::avatarFetched); + disconnect(Choqok::MediaManager::self(), &Choqok::MediaManager::fetchError, + this, &TwitterApiWhoisWidget::avatarFetchError); } } void TwitterApiWhoisWidget::avatarFetchError(const QUrl &remoteUrl, const QString &errMsg) { qCDebug(CHOQOK); Q_UNUSED(errMsg); if (remoteUrl == d->currentPost.author.profileImageUrl) { ///Avatar fetching is failed! but will not disconnect to get the img if it fetches later! const QUrl url(QLatin1String("img://profileImage")); d->wid->document()->addResource(QTextDocument::ImageResource, url, QIcon::fromTheme(QLatin1String("image-missing")).pixmap(48)); updateHtml(); } } void TwitterApiWhoisWidget::updateHtml() { qCDebug(CHOQOK); QString html; if (d->errorMessage.isEmpty()) { QString url = d->currentPost.author.homePageUrl.isEmpty() ? QString() : QStringLiteral("%1").arg(d->currentPost.author.homePageUrl.toDisplayString()); QString mainTable = QString(QLatin1String("\ \
\
%1
\
%2

\ @%3 %4%5
\ %6
\ %7
")) .arg(d->imgActions) .arg(d->currentPost.author.realName.toHtmlEscaped()) .arg(d->currentPost.author.userName).arg(d->currentPost.author.location.toHtmlEscaped()) .arg(!d->timeZone.isEmpty() ? QLatin1Char('(') + d->timeZone + QLatin1Char(')') : QString()) .arg(d->currentPost.author.description) .arg(url); QString countTable = QString(QLatin1String("\ \ \ \
%1
") + i18nc("User posts", "Posts") + QLatin1String("
%2
") + i18nc("User friends", "Friends") + QLatin1String("
%3
") + i18nc("User followers" , "Followers") + QLatin1String("

")) .arg(d->statusesCount) .arg(d->friendsCount) .arg(d->followersCount); html = mainTable + countTable; if (!d->currentPost.content.isEmpty()) { html.append(i18n("Last Status: %1
", d->currentPost.content)); } } else { html = i18n("

%1

", d->errorMessage); } d->wid->setHtml(html); } void TwitterApiWhoisWidget::showForm() { qCDebug(CHOQOK); QPoint pos = d->waitFrame->pos(); d->waitFrame->deleteLater(); d->wid->resize(320, 200); d->wid->document()->setTextWidth(width() - 2); d->wid->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); int h = d->wid->document()->size().toSize().height() + 10; d->wid->setMinimumHeight(h); d->wid->setMaximumHeight(h); this->resize(320, h + 4); int desktopHeight = QApplication::desktop()->height(); int desktopWidth = QApplication::desktop()->width(); if ((pos.x() + this->width()) > desktopWidth) { pos.setX(desktopWidth - width()); } if ((pos.y() + this->height()) > desktopHeight) { pos.setY(desktopHeight - height()); } move(pos); QWidget::show(); } void TwitterApiWhoisWidget::show(QPoint pos) { qCDebug(CHOQOK); d->waitFrame = new QFrame(this); d->waitFrame->setFrameShape(NoFrame); d->waitFrame->setWindowFlags(Qt::Popup); KAnimatedButton *waitButton = new KAnimatedButton; waitButton->setToolTip(i18n("Please wait...")); - connect( waitButton, SIGNAL(clicked(bool)), SLOT(slotCancel()) ); + connect(waitButton, &KAnimatedButton::clicked, this, &TwitterApiWhoisWidget::slotCancel); waitButton->setAnimationPath(QLatin1String("process-working-kde")); waitButton->start(); QVBoxLayout *ly = new QVBoxLayout(d->waitFrame); ly->setSpacing(0); ly->setContentsMargins(0, 0, 0, 0); ly->addWidget(waitButton); d->waitFrame->move(pos - QPoint(15, 15)); d->waitFrame->show(); } void TwitterApiWhoisWidget::checkAnchor(const QUrl url) { qCDebug(CHOQOK); if (url.scheme() == QLatin1String("choqok")) { if (url.host() == QLatin1String("close")) { this->close(); } else if (url.host() == QLatin1String("subscribe")) { d->mBlog->createFriendship(d->currentAccount, d->username); - connect(d->mBlog, SIGNAL(friendshipCreated(Choqok::Account*,QString)), - SLOT(slotFriendshipCreated(Choqok::Account*,QString))); + connect(d->mBlog, &TwitterApiMicroBlog::friendshipCreated, + this, &TwitterApiWhoisWidget::slotFriendshipCreated); } else if (url.host() == QLatin1String("unsubscribe")) { d->mBlog->destroyFriendship(d->currentAccount, d->username); - connect(d->mBlog, SIGNAL(friendshipDestroyed(Choqok::Account*,QString)), - SLOT(slotFriendshipDestroyed(Choqok::Account*,QString))); + connect(d->mBlog, &TwitterApiMicroBlog::friendshipDestroyed, + this, &TwitterApiWhoisWidget::slotFriendshipDestroyed); } else if (url.host() == QLatin1String("block")) { d->mBlog->blockUser(d->currentAccount, d->username); // connect(d->mBlog, SIGNAL(userBlocked(Choqok::Account*,QString)), SLOT(slotUserBlocked(Choqok::Account*,QString))); } } else { Choqok::openUrl(url); close(); } } void TwitterApiWhoisWidget::setupUi() { qCDebug(CHOQOK); d->wid->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://close")), QIcon::fromTheme(QLatin1String("dialog-close")).pixmap(16)); QString style = QLatin1String("color: %1; background-color: %2"); if (Choqok::AppearanceSettings::isCustomUi()) { setStyleSheet(style.arg(Choqok::AppearanceSettings::readForeColor().name()) .arg(Choqok::AppearanceSettings::readBackColor().name())); } else { QPalette p = window()->palette(); setStyleSheet(style.arg(p.color(QPalette::WindowText).name()).arg(p.color(QPalette::Window).name())); } } void TwitterApiWhoisWidget::slotCancel() { qCDebug(CHOQOK); if (d->waitFrame) { d->waitFrame->deleteLater(); } if (d->job) { d->job->kill(); } this->close(); } void TwitterApiWhoisWidget::setActionImages() { d->imgActions.clear(); if (d->username.compare(d->currentAccount->username(), Qt::CaseInsensitive) != 0) { if (d->currentAccount->friendsList().contains(d->username, Qt::CaseInsensitive)) { d->wid->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://unsubscribe")), QIcon::fromTheme(QLatin1String("list-remove-user")).pixmap(16)); d->imgActions += QLatin1String(" "); } else { d->wid->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://subscribe")), QIcon::fromTheme(QLatin1String("list-add-user")).pixmap(16)); d->imgActions += QLatin1String(" "); } d->wid->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://block")), QIcon::fromTheme(QLatin1String("dialog-cancel")).pixmap(16)); d->imgActions += QLatin1String(""); } } void TwitterApiWhoisWidget::slotFriendshipCreated(Choqok::Account *theAccount, const QString &username) { if (theAccount == d->currentAccount && username == d->username) { setActionImages(); updateHtml(); } } void TwitterApiWhoisWidget::slotFriendshipDestroyed(Choqok::Account *theAccount, const QString &username) { if (theAccount == d->currentAccount && username == d->username) { setActionImages(); updateHtml(); } } // void TwitterApiWhoisWidget::slotUserBlocked(Choqok::Account* theAccount, const QString &username) // { // if(theAccount == d->currentAccount && username == d->username){ // Choqok::NotifyManager::success( i18n("Your posts are blocked for %1.", username) ); // } // } diff --git a/libchoqok/dbushandler.cpp b/libchoqok/dbushandler.cpp index fec307bf..647ba624 100644 --- a/libchoqok/dbushandler.cpp +++ b/libchoqok/dbushandler.cpp @@ -1,159 +1,160 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny Copyright (C) 2010-2011 Emanuele Bigiarini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "dbushandler.h" #include #include #include #include #include "ChoqokAdaptor.h" #include "choqokbehaviorsettings.h" #include "libchoqokdebug.h" #include "quickpost.h" #include "shortenmanager.h" #include "uploadmediadialog.h" namespace Choqok { DbusHandler *DbusHandler::m_self = 0; DbusHandler::DbusHandler() { m_self = this; new ChoqokAdaptor(this); QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.choqok")); QDBusConnection::sessionBus().registerObject(QLatin1String("/"), this); } DbusHandler::~DbusHandler() { } QString DbusHandler::prepareUrl(const QString &url) { if (Choqok::BehaviorSettings::shortenOnPaste() && url.count() > 30) { return ShortenManager::self()->shortenUrl(url); } else { return url; } } void DbusHandler::shareUrl(const QString &url, bool title) { if (title) { QByteArray data; KIO::StoredTransferJob *job = KIO::storedGet(QUrl(url), KIO::NoReload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; } else { - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotTitleUrl(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &DbusHandler::slotTitleUrl); job->start(); } } postText(prepareUrl(url)); } void DbusHandler::slotTitleUrl(KJob *job) { QString text; if (!job) { qCWarning(CHOQOK) << "NULL Job returned"; return; } KIO::StoredTransferJob *stj = qobject_cast (job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { QByteArray data = stj->data(); QTextCodec *codec = QTextCodec::codecForHtml(data); m_doc.setHtml(codec->toUnicode(data)); text.append(m_doc.metaInformation(QTextDocument::DocumentTitle)); } QString url = stj->url().toDisplayString(); text.append(QLatin1Char(' ') + prepareUrl(url)); postText(text); } void DbusHandler::uploadFile(const QString &filename) { QPointer dlg = new Choqok::UI::UploadMediaDialog(0, filename); dlg->show(); } void DbusHandler::postText(const QString &text) { // Before posting text ensure QuickPost widget has been created otherwise wait for it. // This is necessary when choqok is launched by a D-Bus call, because it can happen // that DBusHandler is ready, but QuickPost widget not yet. if (Choqok::UI::Global::quickPostWidget() == 0) { m_textToPost = QString(text); - connect(Choqok::UI::Global::mainWindow(), SIGNAL(quickPostCreated()), SLOT(slotcreatedQuickPost())); + connect(Choqok::UI::Global::mainWindow(), &UI::MainWindow::quickPostCreated, + this, &DbusHandler::slotcreatedQuickPost); return; } if (Choqok::UI::Global::quickPostWidget()->isVisible()) { Choqok::UI::Global::quickPostWidget()->appendText(text); } else { Choqok::UI::Global::quickPostWidget()->setText(text); } } void DbusHandler::slotcreatedQuickPost() { if (Choqok::UI::Global::quickPostWidget()->isVisible()) { Choqok::UI::Global::quickPostWidget()->appendText(m_textToPost); } else { Choqok::UI::Global::quickPostWidget()->setText(m_textToPost); } } void DbusHandler::updateTimelines() { Choqok::UI::Global::mainWindow()->action("update_timeline")->trigger(); } void DbusHandler::setShortening(bool flag) { Choqok::BehaviorSettings::setShortenOnPaste(flag); } bool DbusHandler::getShortening() { return Choqok::BehaviorSettings::shortenOnPaste(); } DbusHandler *ChoqokDbus() { if (DbusHandler::m_self == 0) { DbusHandler::m_self = new DbusHandler(); } return DbusHandler::m_self; } } diff --git a/libchoqok/mediamanager.cpp b/libchoqok/mediamanager.cpp index b4cab548..b2849905 100644 --- a/libchoqok/mediamanager.cpp +++ b/libchoqok/mediamanager.cpp @@ -1,242 +1,240 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "mediamanager.h" #include #include #include #include #include #include #include #include #include #include #include "choqokbehaviorsettings.h" #include "choqokuiglobal.h" #include "libchoqokdebug.h" #include "pluginmanager.h" #include "uploader.h" namespace Choqok { class MediaManager::Private { public: Private() : emoticons(KEmoticons().theme()), cache(QLatin1String("choqok-userimages"), 30000000), uploader(0) {} KEmoticonsTheme emoticons; KImageCache cache; QHash queue; QPixmap defaultImage; Uploader *uploader; }; MediaManager::MediaManager() : QObject(qApp), d(new Private) { d->defaultImage = QIcon::fromTheme(QLatin1String("image-loading")).pixmap(48); } MediaManager::~MediaManager() { delete d; mSelf = nullptr; } MediaManager *MediaManager::mSelf = nullptr; MediaManager *MediaManager::self() { if (!mSelf) { mSelf = new MediaManager; } return mSelf; } QPixmap &MediaManager::defaultImage() { return d->defaultImage; } QString MediaManager::parseEmoticons(const QString &text) { return d->emoticons.parseEmoticons(text, KEmoticonsTheme::DefaultParse, QStringList() << QLatin1String("(e)")); } QPixmap MediaManager::fetchImage(const QUrl &remoteUrl, ReturnMode mode /*= Sync*/) { QPixmap p; if (d->cache.findPixmap(remoteUrl.toDisplayString(), &p)) { Q_EMIT imageFetched(remoteUrl, p); } else if (mode == Async) { if (d->queue.values().contains(remoteUrl)) { ///The file is on the way, wait to download complete. return p; } KIO::StoredTransferJob *job = KIO::storedGet(remoteUrl, KIO::NoReload, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "Cannot create a FileCopyJob!"; QString errMsg = i18n("Cannot create a KDE Job. Please check your installation."); Q_EMIT fetchError(remoteUrl, errMsg); return p; } d->queue.insert(job, remoteUrl); - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotImageFetched(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &MediaManager::slotImageFetched); job->start(); } return p; } void MediaManager::slotImageFetched(KJob *job) { KIO::StoredTransferJob *baseJob = qobject_cast(job); QUrl remote = d->queue.value(job); d->queue.remove(job); int responseCode = 0; if (baseJob->metaData().contains(QStringLiteral("responsecode"))) { responseCode = baseJob->queryMetaData(QStringLiteral("responsecode")).toInt(); } if (job->error() || (responseCode > 399 && responseCode < 600)) { qCCritical(CHOQOK) << "Job error:" << job->error() << "\t" << job->errorString(); qCCritical(CHOQOK) << "HTTP response code" << responseCode; QString errMsg = i18n("Cannot download image from %1.", job->errorString()); Q_EMIT fetchError(remote, errMsg); } else { QPixmap p; if (p.loadFromData(baseJob->data())) { d->cache.insertPixmap(remote.toDisplayString(), p); Q_EMIT imageFetched(remote, p); } else { qCCritical(CHOQOK) << "Cannot parse reply from " << baseJob->url().toDisplayString(); Q_EMIT fetchError(remote, i18n("The request failed. Cannot get image file.")); } } } void MediaManager::clearImageCache() { d->cache.clear(); } QPixmap MediaManager::convertToGrayScale(const QPixmap &pic) { QImage result = pic.toImage(); for (int y = 0; y < result.height(); ++y) { for (int x = 0; x < result.width(); ++x) { int pixel = result.pixel(x, y); int gray = qGray(pixel); int alpha = qAlpha(pixel); result.setPixel(x, y, qRgba(gray, gray, gray, alpha)); } } return QPixmap::fromImage(result); } void MediaManager::uploadMedium(const QUrl &localUrl, const QString &pluginId) { QString pId = pluginId; if (pId.isEmpty()) { pId = Choqok::BehaviorSettings::lastUsedUploaderPlugin(); } if (pId.isEmpty()) { Q_EMIT mediumUploadFailed(localUrl, i18n("No pluginId specified, And last used plugin is null.")); return; } if (!d->uploader) { Plugin *plugin = PluginManager::self()->loadPlugin(pId); d->uploader = qobject_cast(plugin); } else if (d->uploader->pluginName() != pId) { // qCDebug(CHOQOK)<<"CREATING A NEW UPLOADER OBJECT"; PluginManager::self()->unloadPlugin(d->uploader->pluginName()); Plugin *plugin = PluginManager::self()->loadPlugin(pId); d->uploader = qobject_cast(plugin); } if (!d->uploader) { return; } KIO::StoredTransferJob *picJob = KIO::storedGet(localUrl, KIO::Reload, KIO::HideProgressInfo); picJob->exec(); if (picJob->error()) { qCritical() << "Job error:" << picJob->errorString(); KMessageBox::detailedError(UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file."), picJob->errorString()); return; } const QByteArray picData = picJob->data(); if (picData.count() == 0) { qCritical() << "Cannot read the media file, please check if it exists."; KMessageBox::error(UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file.")); return; } - connect(d->uploader, SIGNAL(mediumUploaded(QUrl,QString)), - this, SIGNAL(mediumUploaded(QUrl,QString))); - connect(d->uploader, SIGNAL(uploadingFailed(QUrl,QString)), - this, SIGNAL(mediumUploadFailed(QUrl,QString))); + connect(d->uploader, &Uploader::mediumUploaded, this, &MediaManager::mediumUploaded); + connect(d->uploader, &Uploader::uploadingFailed, this, &MediaManager::mediumUploadFailed); const QMimeDatabase db; d->uploader->upload(localUrl, picData, db.mimeTypeForUrl(localUrl).name().toLocal8Bit()); } QByteArray MediaManager::createMultipartFormData(const QMap< QString, QByteArray > &formdata, const QList< QMap< QString, QByteArray > > &mediaFiles) { QByteArray newLine("\r\n"); QString formHeader(QLatin1String(newLine) + QLatin1String("Content-Disposition: form-data; name=\"%1\"")); QByteArray header("--AaB03x"); QByteArray footer("--AaB03x--"); QString fileHeader(QLatin1String(newLine) + QLatin1String("Content-Disposition: file; name=\"%1\"; filename=\"%2\"")); QByteArray data; data.append(header); if (!mediaFiles.isEmpty()) { QList< QMap< QString, QByteArray > >::const_iterator it1 = mediaFiles.constBegin(); QList< QMap< QString, QByteArray > >::const_iterator endIt1 = mediaFiles.constEnd(); for (; it1 != endIt1; ++it1) { data.append(fileHeader.arg(QLatin1String(it1->value(QLatin1String("name")).data())).arg(QLatin1String(it1->value(QLatin1String("filename")).data())).toUtf8()); data.append(newLine + "Content-Type: " + it1->value(QLatin1String("mediumType"))); data.append(newLine); data.append(newLine + it1->value(QLatin1String("medium"))); } } for (const QString &key: formdata.keys()) { data.append(newLine); data.append(header); data.append(formHeader.arg(key).toLatin1()); data.append(newLine); data.append(newLine + formdata.value(key)); } data.append(newLine); data.append(footer); return data; } } diff --git a/libchoqok/microblog.cpp b/libchoqok/microblog.cpp index 9b2d29e4..96a197d2 100644 --- a/libchoqok/microblog.cpp +++ b/libchoqok/microblog.cpp @@ -1,233 +1,234 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "microblog.h" #include #include #include #include "account.h" #include "accountmanager.h" #include "choqokbehaviorsettings.h" #include "composerwidget.h" #include "libchoqokdebug.h" #include "microblogwidget.h" #include "postwidget.h" #include "timelinewidget.h" namespace Choqok { class MicroBlog::Private { public: QString serviceName; QString homepage; QStringList timelineTypes; QTimer *saveTimelinesTimer; }; MicroBlog::MicroBlog(const QString &componentName, QObject *parent) : Plugin(componentName, parent), d(new Private) { qCDebug(CHOQOK); d->saveTimelinesTimer = new QTimer(this); d->saveTimelinesTimer->setInterval(BehaviorSettings::notifyInterval() * 60000); - connect(d->saveTimelinesTimer, SIGNAL(timeout()), SIGNAL(saveTimelines())); - connect(BehaviorSettings::self(), SIGNAL(configChanged()), this, SLOT(slotConfigChanged())); + connect(d->saveTimelinesTimer, &QTimer::timeout, this, &MicroBlog::saveTimelines); + connect(BehaviorSettings::self(), &BehaviorSettings::configChanged, this, + &MicroBlog::slotConfigChanged); d->saveTimelinesTimer->start(); } MicroBlog::~MicroBlog() { qCDebug(CHOQOK); delete d; } QMenu *MicroBlog::createActionsMenu(Account *, QWidget *parent) { return new QMenu(parent); } QString MicroBlog::serviceName() const { return d->serviceName; } QString MicroBlog::homepageUrl() const { return d->homepage; } QString MicroBlog::errorString(ErrorType type) { switch (type) { case ServerError: return i18n("The server returned an error"); break; case CommunicationError: return i18n("Error on communication with server"); break; case ParsingError: return i18n("Error on parsing results"); break; case AuthenticationError: return i18n("Authentication error"); break; case NotSupportedError: return i18n("The server does not support this feature"); break; case OtherError: return i18n("Unknown error"); break; }; return QString(); } void MicroBlog::setServiceName(const QString &serviceName) { d->serviceName = serviceName; } void MicroBlog::setServiceHomepageUrl(const QString &homepage) { d->homepage = homepage; } QStringList MicroBlog::timelineNames() const { return d->timelineTypes; } void MicroBlog::setTimelineNames(const QStringList &types) { d->timelineTypes = types; } void MicroBlog::addTimelineName(const QString &name) { d->timelineTypes << name; } bool MicroBlog::isValidTimeline(const QString &timeline) { return d->timelineTypes.contains(timeline); } void MicroBlog::slotConfigChanged() { d->saveTimelinesTimer->setInterval(BehaviorSettings::notifyInterval() * 60000); } /// UI Objects: Account *MicroBlog::createNewAccount(const QString &alias) { Choqok::Account *acc = Choqok::AccountManager::self()->findAccount(alias); if (!acc) { return new Choqok::Account(this, alias); } else { return 0; } } UI::MicroBlogWidget *MicroBlog::createMicroBlogWidget(Account *account, QWidget *parent) { return new UI::MicroBlogWidget(account, parent); } UI::ComposerWidget *MicroBlog::createComposerWidget(Account *account, QWidget *parent) { return new UI::ComposerWidget(account, parent); } UI::TimelineWidget *MicroBlog::createTimelineWidget(Account *account, const QString &timelineName, QWidget *parent) { return new UI::TimelineWidget(account, timelineName, parent); } UI::PostWidget *MicroBlog::createPostWidget(Account *account, Choqok::Post *post, QWidget *parent) { return new UI::PostWidget(account, post, parent); } TimelineInfo *MicroBlog::timelineInfo(const QString &) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; return 0; } void MicroBlog::abortAllJobs(Account *) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } void MicroBlog::abortCreatePost(Account *, Post *) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } void MicroBlog::createPost(Account *, Post *) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } void MicroBlog::fetchPost(Account *, Post *) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } void MicroBlog::removePost(Account *, Post *) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } void MicroBlog::updateTimelines(Account *) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } QList< Post * > MicroBlog::loadTimeline(Account *, const QString &) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; return QList(); } void MicroBlog::saveTimeline(Account *, const QString &, const QList< UI::PostWidget * > &) { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; } QUrl MicroBlog::postUrl(Account *, const QString &, const QString &) const { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; return QUrl(); } QUrl MicroBlog::profileUrl(Account *, const QString &) const { qCWarning(CHOQOK) << "MicroBlog Plugin should implement this!"; return QUrl(); } } diff --git a/libchoqok/notifymanager.cpp b/libchoqok/notifymanager.cpp index 7424de8e..998100b0 100644 --- a/libchoqok/notifymanager.cpp +++ b/libchoqok/notifymanager.cpp @@ -1,116 +1,117 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "notifymanager.h" #include #include #include "choqokbehaviorsettings.h" #include "choqokuiglobal.h" namespace Choqok { class NotifyManagerPrivate { public: NotifyManagerPrivate() { lastErrorClearance.setSingleShot(true); lastErrorClearance.setInterval(3000); - QObject::connect(&lastErrorClearance, SIGNAL(timeout()), - Choqok::UI::Global::SessionManager::self(), SLOT(resetNotifyManager())); + QObject::connect(&lastErrorClearance, &QTimer::timeout, + Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::resetNotifyManager); } void triggerNotify(const QString &eventId, const QString &title, const QString &message, KNotification::NotificationFlags flags = KNotification::CloseOnTimeout); QList lastErrorMessages; QTimer lastErrorClearance; }; Q_GLOBAL_STATIC(NotifyManagerPrivate, _nmp) NotifyManager::NotifyManager() { } NotifyManager::~NotifyManager() { } void NotifyManager::resetNotifyManager() { _nmp->lastErrorMessages.clear(); } void NotifyManager::success(const QString &message, const QString &title) { if (Choqok::UI::Global::mainWindow()->isActiveWindow()) { choqokMainWindow->showStatusMessage(message); } else { _nmp->triggerNotify(QLatin1String("job-success"), title, message); } } void NotifyManager::error(const QString &message, const QString &title) { if (!_nmp->lastErrorMessages.contains(message)) { _nmp->triggerNotify(QLatin1String("job-error"), title, message); _nmp->lastErrorMessages.append(message); _nmp->lastErrorClearance.start(); } } void NotifyManager::newPostArrived(const QString &message, const QString &title) { QString fullMsg = QStringLiteral("%1:
%2").arg(title).arg(message); if (Choqok::UI::Global::mainWindow()->isActiveWindow()) { choqokMainWindow->showStatusMessage(message); } else { if (Choqok::BehaviorSettings::knotify()) { KNotification *n = new KNotification(QLatin1String("new-post-arrived"), choqokMainWindow); n->setActions(QStringList(i18nc("Show Choqok MainWindow", "Show Choqok"))); n->setText(fullMsg); - QObject::connect(n, SIGNAL(activated(uint)), choqokMainWindow, SLOT(activateChoqok())); + QObject::connect(n, (void (KNotification::*)())&KNotification::activated, + choqokMainWindow, &Choqok::UI::MainWindow::activateChoqok); n->sendEvent(); } } } void NotifyManager::shortening(const QString &message, const QString &title) { _nmp->triggerNotify(QLatin1String("shortening"), title, message); } void NotifyManagerPrivate::triggerNotify(const QString &eventId, const QString &title, const QString &message, KNotification::NotificationFlags flags) { QString fullMsg = QStringLiteral("%1:
%2").arg(title).arg(message); KNotification::event(eventId, fullMsg, QPixmap(), Choqok::UI::Global::mainWindow(), flags); } } diff --git a/libchoqok/pluginmanager.cpp b/libchoqok/pluginmanager.cpp index 2b0d5de8..2d25681e 100644 --- a/libchoqok/pluginmanager.cpp +++ b/libchoqok/pluginmanager.cpp @@ -1,468 +1,468 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pluginmanager.h" #include #include #include #include #include #include #include "accountmanager.h" #include "libchoqokdebug.h" namespace Choqok { class PluginManagerPrivate { public: PluginManagerPrivate() : shutdownMode(StartingUp), isAllPluginsLoaded(false) { plugins = KPluginInfo::fromServices(KServiceTypeTrader::self()->query(QLatin1String("Choqok/Plugin"), QStringLiteral("[X-Choqok-Version] == %1").arg(CHOQOK_PLUGIN_VERSION))); } ~PluginManagerPrivate() { if (shutdownMode != DoneShutdown) { qCWarning(CHOQOK) << "Destructing plugin manager without going through the shutdown process!" << endl; } // Clean up loadedPlugins manually, because PluginManager can't access our global // static once this destructor has started. for (const KPluginInfo &p: loadedPlugins.keys()) { Plugin *plugin = loadedPlugins.value(p); qCWarning(CHOQOK) << "Deleting stale plugin '" << plugin->objectName() << "'"; plugin->disconnect(&instance, SLOT(slotPluginDestroyed(QObject*))); plugin->deleteLater();; loadedPlugins.remove(p); } } // All available plugins, regardless of category, and loaded or not QList plugins; // Dict of all currently loaded plugins, mapping the KPluginInfo to // a plugin typedef QMap InfoToPluginMap; InfoToPluginMap loadedPlugins; // The plugin manager's mode. The mode is StartingUp until loadAllPlugins() // has finished loading the plugins, after which it is set to Running. // ShuttingDown and DoneShutdown are used during Choqok shutdown by the // async unloading of plugins. enum ShutdownMode { StartingUp, Running, ShuttingDown, DoneShutdown }; ShutdownMode shutdownMode; // Plugins pending for loading QStack pluginsToLoad; bool isAllPluginsLoaded; PluginManager instance; }; Q_GLOBAL_STATIC(PluginManagerPrivate, _kpmp) PluginManager *PluginManager::self() { return &_kpmp->instance; } PluginManager::PluginManager() : QObject() { - connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), - this, SLOT(slotAboutToQuit())); + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, + this, &PluginManager::slotAboutToQuit); } PluginManager::~PluginManager() { } QList PluginManager::availablePlugins(const QString &category) const { if (category.isEmpty()) { return _kpmp->plugins; } QList result; for (const KPluginInfo &p: _kpmp->plugins) { if ((p.category().compare(category) == 0) && !p.service()->noDisplay()) { result.append(p); } } return result; } PluginList PluginManager::loadedPlugins(const QString &category) const { PluginList result; for (const KPluginInfo &p: _kpmp->loadedPlugins.keys()) { if (category.isEmpty() || p.category().compare(category) == 0) { result.append(_kpmp->loadedPlugins.value(p)); } } return result; } KPluginInfo PluginManager::pluginInfo(const Plugin *plugin) const { for (const KPluginInfo &p: _kpmp->loadedPlugins.keys()) { if (_kpmp->loadedPlugins.value(p) == plugin) { return p; } } return KPluginInfo(); } void PluginManager::shutdown() { qCDebug(CHOQOK); if (_kpmp->shutdownMode != PluginManagerPrivate::Running) { qCDebug(CHOQOK) << "called when not running. / state =" << _kpmp->shutdownMode; return; } _kpmp->shutdownMode = PluginManagerPrivate::ShuttingDown; // Remove any pending plugins to load, we're shutting down now :) _kpmp->pluginsToLoad.clear(); // Ask all plugins to unload for (PluginManagerPrivate::InfoToPluginMap::ConstIterator it = _kpmp->loadedPlugins.constBegin(); it != _kpmp->loadedPlugins.constEnd(); /* EMPTY */) { // Plugins could emit their ready for unload signal directly in response to this, // which would invalidate the current iterator. Therefore, we copy the iterator // and increment it beforehand. PluginManagerPrivate::InfoToPluginMap::ConstIterator current(it); ++it; // FIXME: a much cleaner approach would be to just delete the plugin now. if it needs // to do some async processing, it can grab a reference to the app itself and create // another object to do it. current.value()->aboutToUnload(); } // When running under valgrind, don't enable the timer because it will almost // certainly fire due to valgrind's much slower processing #if defined(HAVE_VALGRIND_H) && !defined(NDEBUG) && defined(__i386__) if (RUNNING_ON_VALGRIND) { qCDebug(CHOQOK) << "Running under valgrind, disabling plugin unload timeout guard"; } else #endif QTimer::singleShot(3000, this, SLOT(slotShutdownTimeout())); } void PluginManager::slotPluginReadyForUnload() { qCDebug(CHOQOK); // Using QObject::sender() is on purpose here, because otherwise all // plugins would have to pass 'this' as parameter, which makes the API // less clean for plugin authors // FIXME: I don't buy the above argument. Add a Choqok::Plugin::emitReadyForUnload(void), // and make readyForUnload be passed a plugin. - Richard Plugin *plugin = dynamic_cast(const_cast(sender())); if (!plugin) { qCWarning(CHOQOK) << "Calling object is not a plugin!"; return; } qCDebug(CHOQOK) << plugin->pluginId() << "ready for unload"; _kpmp->loadedPlugins.remove(_kpmp->loadedPlugins.key(plugin)); plugin->deleteLater(); plugin = nullptr; if (_kpmp->loadedPlugins.count() < 1) { slotShutdownDone(); } } void PluginManager::slotShutdownTimeout() { qCDebug(CHOQOK); // When we were already done the timer might still fire. // Do nothing in that case. if (_kpmp->shutdownMode == PluginManagerPrivate::DoneShutdown) { return; } QStringList remaining; for (Plugin *p: _kpmp->loadedPlugins.values()) { remaining.append(p->pluginId()); } qCWarning(CHOQOK) << "Some plugins didn't shutdown in time!" << endl << "Remaining plugins:" << remaining << endl << "Forcing Choqok shutdown now." << endl; slotShutdownDone(); } void PluginManager::slotShutdownDone() { qCDebug(CHOQOK) ; _kpmp->shutdownMode = PluginManagerPrivate::DoneShutdown; } void PluginManager::loadAllPlugins() { qCDebug(CHOQOK); KSharedConfig::Ptr config = KSharedConfig::openConfig(); if (config->hasGroup(QLatin1String("Plugins"))) { QMap pluginsMap; const QMap entries = config->entryMap(QLatin1String("Plugins")); for (const QString &key: entries.keys()) { if (key.endsWith(QLatin1String("Enabled"))) { pluginsMap.insert(key.left(key.length() - 7), (entries.value(key).compare(QLatin1String("true")) == 0)); } } for (const KPluginInfo &p: availablePlugins(QString::null)) { //krazy:exclude=nullstrassign for old broken gcc if ((p.category().compare(QLatin1String("MicroBlogs")) == 0) || (p.category().compare(QLatin1String("Shorteners")) == 0)) { continue; } const QString pluginName = p.pluginName(); if (pluginsMap.value(pluginName, p.isPluginEnabledByDefault())) { if (!plugin(pluginName)) { _kpmp->pluginsToLoad.push(pluginName); } } else { //This happens if the user unloaded plugins with the config plugin page. // No real need to be assync because the user usually unload few plugins // compared tto the number of plugin to load in a cold start. - Olivier if (plugin(pluginName)) { unloadPlugin(pluginName); } } } } else { // we had no config, so we load any plugins that should be loaded by default. for (const KPluginInfo &p: availablePlugins(QString::null)) { //krazy:exclude=nullstrassign for old broken gcc if ((p.category().compare(QLatin1String("MicroBlogs")) == 0) || (p.category().compare(QLatin1String("Shorteners")) == 0)) { continue; } if (p.isPluginEnabledByDefault()) { _kpmp->pluginsToLoad.push(p.pluginName()); } } } // Schedule the plugins to load QTimer::singleShot(0, this, SLOT(slotLoadNextPlugin())); } void PluginManager::slotLoadNextPlugin() { qCDebug(CHOQOK); if (_kpmp->pluginsToLoad.isEmpty()) { if (_kpmp->shutdownMode == PluginManagerPrivate::StartingUp) { _kpmp->shutdownMode = PluginManagerPrivate::Running; _kpmp->isAllPluginsLoaded = true; qCDebug(CHOQOK) << "All plugins loaded..."; Q_EMIT allPluginsLoaded(); } return; } QString key = _kpmp->pluginsToLoad.pop(); loadPluginInternal(key); // Schedule the next run unconditionally to avoid code duplication on the // allPluginsLoaded() signal's handling. This has the added benefit that // the signal is delayed one event loop, so the accounts are more likely // to be instantiated. QTimer::singleShot(0, this, SLOT(slotLoadNextPlugin())); } Plugin *PluginManager::loadPlugin(const QString &_pluginId, PluginLoadMode mode /* = LoadSync */) { QString pluginId = _pluginId; // Try to find legacy code // FIXME: Find any cases causing this, remove them, and remove this too - Richard if (pluginId.endsWith(QLatin1String(".desktop"))) { qCWarning(CHOQOK) << "Trying to use old-style API!" << endl; pluginId = pluginId.remove(QRegExp(QLatin1String(".desktop$"))); } if (mode == LoadSync) { return loadPluginInternal(pluginId); } else { _kpmp->pluginsToLoad.push(pluginId); QTimer::singleShot(0, this, SLOT(slotLoadNextPlugin())); return nullptr; } } Plugin *PluginManager::loadPluginInternal(const QString &pluginId) { qCDebug(CHOQOK) << "Loading Plugin:" << pluginId; KPluginInfo info = infoForPluginId(pluginId); if (!info.isValid()) { qCWarning(CHOQOK) << "Unable to find a plugin named '" << pluginId << "'!"; return nullptr; } if (_kpmp->loadedPlugins.contains(info)) { return _kpmp->loadedPlugins[ info ]; } QString error; Plugin *plugin = KServiceTypeTrader::createInstanceFromQuery(QLatin1String("Choqok/Plugin"), QStringLiteral("[X-KDE-PluginInfo-Name]=='%1'").arg(pluginId), this, QVariantList(), &error); if (plugin) { _kpmp->loadedPlugins.insert(info, plugin); info.setPluginEnabled(true); - connect(plugin, SIGNAL(destroyed(QObject*)), this, SLOT(slotPluginDestroyed(QObject*))); - connect(plugin, SIGNAL(readyForUnload()), this, SLOT(slotPluginReadyForUnload())); + connect(plugin, &Plugin::destroyed, this, &PluginManager::slotPluginDestroyed); + connect(plugin, &Plugin::readyForUnload, this, &PluginManager::slotPluginReadyForUnload); qCDebug(CHOQOK) << "Successfully loaded plugin '" << pluginId << "'"; if (plugin->pluginInfo().category() != QLatin1String("MicroBlogs") && plugin->pluginInfo().category() != QLatin1String("Shorteners")) { qCDebug(CHOQOK) << "Emitting pluginLoaded()"; Q_EMIT pluginLoaded(plugin); } // Protocol* protocol = dynamic_cast( plugin ); // if ( protocol ) // emit protocolLoaded( protocol ); } else { qCDebug(CHOQOK) << "Loading plugin" << pluginId << "failed, KServiceTypeTrader reported error:" << error ; } return plugin; } bool PluginManager::unloadPlugin(const QString &spec) { qCDebug(CHOQOK) << spec; if (Plugin *thePlugin = plugin(spec)) { qCDebug(CHOQOK) << "Unloading" << spec; thePlugin->aboutToUnload(); return true; } else { return false; } } void PluginManager::slotPluginDestroyed(QObject *plugin) { qCDebug(CHOQOK); for (const KPluginInfo &p: _kpmp->loadedPlugins.keys()) { if (_kpmp->loadedPlugins.value(p) == plugin) { const QString pluginName = p.pluginName(); _kpmp->loadedPlugins.remove(p); Q_EMIT pluginUnloaded(pluginName); break; } } if (_kpmp->shutdownMode == PluginManagerPrivate::ShuttingDown && _kpmp->loadedPlugins.isEmpty()) { // Use a timer to make sure any pending deleteLater() calls have // been handled first QTimer::singleShot(0, this, SLOT(slotShutdownDone())); } } Plugin *PluginManager::plugin(const QString &_pluginId) const { // Hack for compatibility with Plugin::pluginId(), which returns // classname() instead of the internal name. Changing that is not easy // as it invalidates the config file, the contact list, and most likely // other code as well. // For now, just transform FooProtocol to choqok_foo. // FIXME: In the future we'll need to change this nevertheless to unify // the handling - Martijn QString pluginId = _pluginId; if (pluginId.endsWith(QLatin1String("Protocol"))) { pluginId = QLatin1String("choqok_") + _pluginId.toLower().remove(QLatin1String("protocol")); } // End hack KPluginInfo info = infoForPluginId(pluginId); if (!info.isValid()) { return nullptr; } if (_kpmp->loadedPlugins.contains(info)) { return _kpmp->loadedPlugins[ info ]; } else { return nullptr; } } KPluginInfo PluginManager::infoForPluginId(const QString &pluginId) const { for (const KPluginInfo &p: _kpmp->plugins) { if (p.pluginName().compare(pluginId) == 0) { return p; } } return KPluginInfo(); } bool PluginManager::setPluginEnabled(const QString &_pluginId, bool enabled /* = true */) { QString pluginId = _pluginId; KConfigGroup config(KSharedConfig::openConfig(), "Plugins"); // FIXME: What is this for? This sort of thing is kconf_update's job - Richard if (!pluginId.startsWith(QLatin1String("choqok_"))) { pluginId.prepend(QLatin1String("choqok_")); } if (!infoForPluginId(pluginId).isValid()) { return false; } config.writeEntry(pluginId + QLatin1String("Enabled"), enabled); config.sync(); return true; } bool PluginManager::isAllPluginsLoaded() const { return _kpmp->isAllPluginsLoaded; } void PluginManager::slotAboutToQuit() { shutdown(); } } //END namespace Choqok diff --git a/libchoqok/ui/choqoktabbar.cpp b/libchoqok/ui/choqoktabbar.cpp index 5411d65b..11d9899f 100644 --- a/libchoqok/ui/choqoktabbar.cpp +++ b/libchoqok/ui/choqoktabbar.cpp @@ -1,874 +1,874 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2011-2012 Mehrdad Momeny Copyright (C) 2011-2012 Bardia Daneshvar This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "choqoktabbar.h" #include #include #include #include #include #include #include #include #include "choqokappearancesettings.h" #define ICON_SMALL_SIZE 22 #define ICON_MEDIUM_SIZE 32 #define ICON_BIG_SIZE 40 namespace Choqok { namespace UI { QList choqok_tabbars_list; class ChoqokTabBarPrivate { public: QToolBar *toolbar; QStackedWidget *st_widget; // QWidget *tab_widget; QWidget *tab_alongside_widget; QGridLayout *main_layout; QGridLayout *stack_wgt_layout; ChoqokTabBar::TabPosition position; ChoqokTabBar::SelectionBehavior selection_behavior; bool tab_closable; bool styled_tabbar; QHash corners_hash; QHash extra_wgt_hash; QList actions_list; QList history_list; QPalette old_palette; }; ChoqokTabBar::ChoqokTabBar(QWidget *parent) : QWidget(parent) { p = new ChoqokTabBarPrivate; p->position = (TabPosition)Choqok::AppearanceSettings::tabBarPosition(); p->styled_tabbar = Choqok::AppearanceSettings::tabBarIsStyled(); p->tab_alongside_widget = 0; p->tab_closable = false; p->selection_behavior = ChoqokTabBar::SelectPreviousTab; // p->tab_widget = new QWidget(); p->st_widget = new QStackedWidget(); p->toolbar = new QToolBar(); p->toolbar->setContextMenuPolicy(Qt::CustomContextMenu); p->stack_wgt_layout = new QGridLayout(); p->stack_wgt_layout->addWidget(p->st_widget , 1 , 1); p->stack_wgt_layout->setContentsMargins(0 , 0 , 0 , 0); p->main_layout = new QGridLayout(this); p->main_layout->setSpacing(0); p->main_layout->setContentsMargins(0 , 0 , 0 , 0); p->main_layout->addLayout(p->stack_wgt_layout , 1 , 1); - connect(p->toolbar , SIGNAL(actionTriggered(QAction*)) , SLOT(action_triggered(QAction*))); - connect(p->toolbar , SIGNAL(customContextMenuRequested(QPoint)) , SLOT(contextMenuRequest(QPoint))); + connect(p->toolbar, &QToolBar::actionTriggered, this, &ChoqokTabBar::action_triggered); + connect(p->toolbar, &QToolBar::customContextMenuRequested, this, &ChoqokTabBar::contextMenuRequest); setToolButtonStyle(Qt::ToolButtonIconOnly); int iconSize = Choqok::AppearanceSettings::tabBarSize(); if (iconSize != ICON_BIG_SIZE && iconSize != ICON_MEDIUM_SIZE && iconSize != ICON_SMALL_SIZE) { iconSize = ICON_MEDIUM_SIZE; } init_position(p->position); setIconSize(QSize(iconSize, iconSize)); init_style(); } void ChoqokTabBar::setTabPosition(ChoqokTabBar::TabPosition position) { if (position == p->position) { return; } p->main_layout->removeWidget(p->toolbar); init_position(position); init_style(); init_alongside_widget(size()); /*! ----------- Setting Up All Linked ChoqokTabBars ------------ */ if (linkedTabBar()) for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) { choqok_tabbars_list.at(i)->setTabPosition(position); } /*! ------------------------------------------------------------ */ Q_EMIT tabPositionChanged(position); } void ChoqokTabBar::init_position(ChoqokTabBar::TabPosition position) { p->position = position; /*! ---------- Adding to the New Layout -------------- */ switch (static_cast(position)) { case ChoqokTabBar::North : p->main_layout->addWidget(p->toolbar , 0 , 1); p->toolbar->setOrientation(Qt::Horizontal); p->toolbar->setSizePolicy(QSizePolicy::MinimumExpanding , QSizePolicy::Minimum); break; case ChoqokTabBar::South : p->main_layout->addWidget(p->toolbar , 2 , 1); p->toolbar->setOrientation(Qt::Horizontal); p->toolbar->setSizePolicy(QSizePolicy::MinimumExpanding , QSizePolicy::Minimum); break; case ChoqokTabBar::West : p->main_layout->addWidget(p->toolbar , 1 , 0); p->toolbar->setOrientation(Qt::Vertical); p->toolbar->setSizePolicy(QSizePolicy::Minimum , QSizePolicy::MinimumExpanding); break; case ChoqokTabBar::East : p->main_layout->addWidget(p->toolbar , 1 , 2); p->toolbar->setOrientation(Qt::Vertical); p->toolbar->setSizePolicy(QSizePolicy::Minimum , QSizePolicy::MinimumExpanding); break; } } ChoqokTabBar::TabPosition ChoqokTabBar::tabPosition() const { return p->position; } void ChoqokTabBar::setTabsClosable(bool closeable) { if (p->tab_closable == closeable) { return; } p->tab_closable = closeable; /*! ----------- Setting Up All Linked ChoqokTabBars ------------ */ if (linkedTabBar()) for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) { choqok_tabbars_list.at(i)->setTabsClosable(closeable); } /*! ------------------------------------------------------------ */ } bool ChoqokTabBar::tabsClosable() const { return p->tab_closable; } void ChoqokTabBar::setCornerWidget(QWidget *w , Qt::Corner corner) { if (p->corners_hash.contains(corner)) { return; } p->corners_hash.insert(corner , w); } QWidget *ChoqokTabBar::cornerWidget(Qt::Corner corner) const { return p->corners_hash.value(corner); } void ChoqokTabBar::setExtraWidget(QWidget *widget , ChoqokTabBar::ExtraWidgetPosition position) { if (p->extra_wgt_hash.contains(position)) { p->extra_wgt_hash.remove(position); } if (p->extra_wgt_hash.values().contains(widget)) { p->extra_wgt_hash.remove(p->extra_wgt_hash.key(widget)); } switch (static_cast(position)) { case ChoqokTabBar::Top : p->stack_wgt_layout->addWidget(widget , 0 , 1); break; case ChoqokTabBar::Bottom : p->stack_wgt_layout->addWidget(widget , 2 , 1); break; case ChoqokTabBar::Left : p->stack_wgt_layout->addWidget(widget , 1 , 0); break; case ChoqokTabBar::Right : p->stack_wgt_layout->addWidget(widget , 1 , 2); break; } p->extra_wgt_hash.insert(position , widget); init_extra_widget(size()); } QWidget *ChoqokTabBar::extraWidget(ExtraWidgetPosition position) { return p->extra_wgt_hash.value(position); } void ChoqokTabBar::setTabAlongsideWidget(QWidget *widget) { p->tab_alongside_widget = widget; init_alongside_widget(size()); } QWidget *ChoqokTabBar::tabAlongsideWidget() const { return p->tab_alongside_widget; } void ChoqokTabBar::setTabCloseActivatePrevious(bool stt) { if (stt) { setSelectionBehaviorOnRemove(ChoqokTabBar::SelectPreviousTab); } else { setSelectionBehaviorOnRemove(ChoqokTabBar::SelectLeftTab); } } bool ChoqokTabBar::tabCloseActivatePrevious() const { return (p->selection_behavior == ChoqokTabBar::SelectPreviousTab); } ChoqokTabBar::SelectionBehavior ChoqokTabBar::selectionBehaviorOnRemove() const { return p->selection_behavior; } void ChoqokTabBar::setSelectionBehaviorOnRemove(ChoqokTabBar::SelectionBehavior behavior) { if (p->selection_behavior == behavior) { return; } p->selection_behavior = behavior; /*! ----------- Setting Up All Linked ChoqokTabBars ------------ */ if (linkedTabBar()) for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) { choqok_tabbars_list.at(i)->setSelectionBehaviorOnRemove(behavior); } /*! ------------------------------------------------------------ */ } QWidget *ChoqokTabBar::currentWidget() const { return p->st_widget->currentWidget(); } QWidget *ChoqokTabBar::widget(int index) const { return p->st_widget->widget(index); } int ChoqokTabBar::currentIndex() const { return p->st_widget->currentIndex(); } int ChoqokTabBar::indexOf(QWidget *widget) const { return p->st_widget->indexOf(widget); } int ChoqokTabBar::addTab(QWidget *widget , const QString &name) { return insertTab(count() , widget , QIcon() , name); } int ChoqokTabBar::addTab(QWidget *widget , const QIcon &icon , const QString &name) { return insertTab(count() , widget , icon , name); } int ChoqokTabBar::insertTab(int index , QWidget *widget , const QString &name) { return insertTab(index , widget , QIcon() , name); } int ChoqokTabBar::insertTab(int index , QWidget *widget , const QIcon &input_icon , const QString &name) { QIcon icon(input_icon); if (input_icon.isNull()) { icon = QIcon::fromTheme(QLatin1String("edit-find")); } QAction *action = new QAction(icon , name , this); action->setCheckable(true); p->actions_list.insert(index , action); p->st_widget->insertWidget(index , widget); - connect(widget , SIGNAL(destroyed(QObject*)) , SLOT(widget_destroyed(QObject*))); + connect(widget, &QWidget::destroyed, this, &ChoqokTabBar::widget_destroyed); for (int i = 0 ; i < p->history_list.count() ; i++) if (p->history_list.at(i) >= index) { p->history_list[ i ]++; } refreshTabBar(); if (count() == 1) { action->trigger(); p->history_list << 0; } return index; } void ChoqokTabBar::moveTab(int from , int to) { int low , high; if (from == to) { return ; } if (from > to) { low = to; high = from; } if (from < to) { low = from; high = to; } p->actions_list.move(from , to); p->st_widget->move(from , to); int shift = (from > to) * 2 - 1; for (int i = 0; i < p->history_list.count() ; i++) { int index = p->history_list.at(i); if (index > low && index < high) { p->history_list[ i ] += shift; } if (index == from) { p->history_list[ i ] = to; } } refreshTabBar(); Q_EMIT tabMoved(from , to); } void ChoqokTabBar::removeTab(int index) { - disconnect(p->st_widget->widget(index) , SIGNAL(destroyed(QObject*)) , this , SLOT(widget_destroyed(QObject*))); + disconnect(p->st_widget->widget(index), &QWidget::destroyed, this, &ChoqokTabBar::widget_destroyed); p->history_list.removeAll(index); p->actions_list.removeAt(index); p->st_widget->removeWidget(p->st_widget->widget(index)); for (int i = 0 ; i < p->history_list.count() ; i++) if (p->history_list.at(i) > index) { p->history_list[ i ]--; } if (!p->history_list.isEmpty()) { p->actions_list[ p->history_list.takeFirst() ]->trigger(); } refreshTabBar(); } void ChoqokTabBar::removePage(QWidget *widget) { removeTab(p->st_widget->indexOf(widget)); } void ChoqokTabBar::setTabIcon(int index , const QIcon &input_icon) { p->actions_list[ index ]->setIcon(input_icon); } QIcon ChoqokTabBar::tabIcon(int index) const { return p->actions_list.at(index)->icon(); } void ChoqokTabBar::setTabText(int index , const QString &text) { p->actions_list[ index ]->setText(text); } QString ChoqokTabBar::tabText(int index) const { return p->actions_list.at(index)->text(); } void ChoqokTabBar::setLinkedTabBar(bool stt) { if (linkedTabBar() == stt) { return; } if (!choqok_tabbars_list.isEmpty() && stt) { ChoqokTabBar *tmp = choqok_tabbars_list.first(); setIconSize(tmp->iconSize()); setStyledTabBar(tmp->styledTabBar()); setTabPosition(tmp->tabPosition()); setSelectionBehaviorOnRemove(tmp->selectionBehaviorOnRemove()); setTabsClosable(tmp->tabsClosable()); setToolButtonStyle(tmp->toolButtonStyle()); } if (stt) { choqok_tabbars_list << this; } else { choqok_tabbars_list.removeOne(this); } } bool ChoqokTabBar::linkedTabBar() const { for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) if (choqok_tabbars_list.at(i) == this) { return true; } return false; } void ChoqokTabBar::setTabBarHidden(bool stt) { p->toolbar->setHidden(stt); } bool ChoqokTabBar::isTabBarHidden() const { return p->toolbar->isHidden(); } QSize ChoqokTabBar::iconSize() const { return p->toolbar->iconSize(); } void ChoqokTabBar::setIconSize(const QSize &size) { if (size == p->toolbar->iconSize()) { return; } p->toolbar->setIconSize(size); /*! ----------- Setting Up All Linked ChoqokTabBars ------------ */ if (linkedTabBar()) for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) { choqok_tabbars_list.at(i)->setIconSize(size); } /*! ------------------------------------------------------------ */ Q_EMIT iconSizeChanged(size); } int ChoqokTabBar::count() const { return p->st_widget->count(); } Qt::ToolButtonStyle ChoqokTabBar::toolButtonStyle() const { return p->toolbar->toolButtonStyle(); } void ChoqokTabBar::setToolButtonStyle(Qt::ToolButtonStyle toolButtonStyle) { if (p->toolbar->toolButtonStyle() == toolButtonStyle) { return; } p->toolbar->setToolButtonStyle(toolButtonStyle); /*! ----------- Setting Up All Linked ChoqokTabBars ------------ */ if (linkedTabBar()) for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) { choqok_tabbars_list.at(i)->setToolButtonStyle(toolButtonStyle); } /*! ------------------------------------------------------------ */ } void ChoqokTabBar::setStyledTabBar(bool stt) { if (p->styled_tabbar == stt) { return; } p->styled_tabbar = stt; init_style(); /*! ----------- Setting Up All Linked ChoqokTabBars ------------ */ if (linkedTabBar()) for (int i = 0 ; i < choqok_tabbars_list.count() ; i++) { choqok_tabbars_list.at(i)->setStyledTabBar(stt); } /*! ------------------------------------------------------------ */ Q_EMIT styledPanelSignal(stt); } bool ChoqokTabBar::styledTabBar() const { return p->styled_tabbar; } void ChoqokTabBar::refreshTabBar() { p->toolbar->clear(); for (int i = 0 ; i < p->actions_list.count() ; i++) { p->toolbar->addAction(p->actions_list.at(i)); } } void ChoqokTabBar::setCurrentIndex(int index) { p->actions_list[ index ]->trigger(); } void ChoqokTabBar::setCurrentWidget(QWidget *widget) { int index = p->st_widget->indexOf(widget); setCurrentIndex(index); } void ChoqokTabBar::action_triggered(QAction *action) { action->setChecked(true); int new_index = p->actions_list.indexOf(action); int old_index = currentIndex(); if (new_index == old_index) { return; } if (old_index != -1) { p->actions_list[ old_index ]->setChecked(false); } p->st_widget->setCurrentIndex(new_index); p->history_list.prepend(new_index); Q_EMIT currentChanged(new_index); } void ChoqokTabBar::init_style() { if (!styledTabBar()) { p->toolbar->setStyleSheet(QString()); return; } /*! ----------------- Setup Colors -------------------- */ QColor tmp = palette().color(QPalette::Active , QPalette::WindowText); QString highlight_back(QLatin1String("rgba(%1,%2,%3,%4)")); highlight_back = highlight_back.arg(QString::number(tmp.red()) , QString::number(tmp.green()) , QString::number(tmp.blue()) , QLatin1String("113")); tmp = palette().color(QPalette::Active , QPalette::WindowText); QString shadow(QLatin1String("rgba(%1,%2,%3,%4)")); shadow = shadow.arg(QString::number(tmp.red()) , QString::number(tmp.green()) , QString::number(tmp.blue()) , QLatin1String("173")); tmp = palette().color(QPalette::Active , QPalette::Highlight); tmp.setHsv(tmp.hue() , tmp.saturation() , tmp.value() / 2); QString alt_highlight(QLatin1String("rgba(%1,%2,%3,%4)")); alt_highlight = alt_highlight.arg(QString::number(tmp.red()) , QString::number(tmp.green()) , QString::number(tmp.blue()) , QLatin1String("255")); /*! -------------------------------------------------- */ p->old_palette = palette(); switch (static_cast(tabPosition())) { case ChoqokTabBar::North : p->toolbar->setStyleSheet( QLatin1String("QToolBar{ " "background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 ") + shadow + QLatin1String(", stop:0.10 ") + alt_highlight + QLatin1String("," " stop:0.90 palette(highlight), stop:1 ") + shadow + QLatin1String(");" "border-style: solid;" "padding: 0px}" "QToolButton{ border-style:solid; background-color: transparent;" "padding-left: 2px;" "padding-right: 2px;" "padding-top: 6px;" "padding-bottom: 6px;" "margin: 0px; }" "QToolButton:checked{ background-color: qconicalgradient(cx:0.5, cy:0.85, angle:90, stop:0 transparent, stop:0.3500 ") + highlight_back + QLatin1String(", stop:0.3700 palette(window), stop:0.6500 palette(window), stop:0.6700 ") + highlight_back + QLatin1String(", stop:1 transparent); }" "QToolButton:hover:!checked{ background-color: qlineargradient(x1:0, y1:3, x2:0, y2:0, stop:0 ") + shadow + QLatin1String(",stop:1 transparent); }") ); break; case ChoqokTabBar::South : p->toolbar->setStyleSheet( QLatin1String("QToolBar{ " "background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 ") + shadow + QLatin1String(", stop:0.10 palette(highlight)," " stop:0.90 ") + alt_highlight + QLatin1String(", stop:1 ") + shadow + QLatin1String(");" "border-style: solid;" "padding: 0px}" "QToolButton{ border-style:solid; background-color: transparent;" "padding-left: 2px;" "padding-right: 2px;" "padding-top: 6px;" "padding-bottom: 6px;" "margin: 0px; }" "QToolButton:checked{ background-color: qconicalgradient(cx:0.5, cy:0.15, angle:270, stop:0 transparent, stop:0.3500 ") + highlight_back + QLatin1String(", stop:0.3700 palette(window), stop:0.6500 palette(window), stop:0.6700 ") + highlight_back + QLatin1String(", stop:1 transparent); }" "QToolButton:hover:!checked{ background-color: qlineargradient(x1:0, y1:-2, x2:0, y2:1, stop:0 ") + shadow + QLatin1String(",stop:1 transparent); }") ); break; case ChoqokTabBar::West : p->toolbar->setStyleSheet( QLatin1String("QToolBar{ " "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 ") + alt_highlight + QLatin1String(", stop:0.90 palette(highlight), " "stop:1 ") + shadow + QLatin1String(");" "border-style: solid;" "padding: 0px}" "QToolButton{ border-style:solid; background-color: transparent;" "padding-left: 6px;" "padding-right: 6px;" "padding-top: 2px;" "padding-bottom: 2px;" "margin: 0px; }" "QToolButton:checked{ background-color: qconicalgradient(cx:0.85, cy:0.5, angle:180, stop:0 transparent, stop:0.3500 ") + highlight_back + QLatin1String(", stop:0.3700 palette(window), stop:0.6500 palette(window), stop:0.6700 ") + highlight_back + QLatin1String(", stop:1 transparent); }" "QToolButton:hover:!checked{ background-color: qlineargradient(x1:3, y1:0, x2:0, y2:0, stop:0 ") + shadow + QLatin1String(",stop:1 transparent); }") ); break; case ChoqokTabBar::East : p->toolbar->setStyleSheet( QLatin1String("QToolBar{ " "background-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 ") + alt_highlight + QLatin1String(", stop:0.90 palette(highlight), " "stop:1 ") + shadow + QLatin1String(");" "border-style: solid;" "padding: 0px}" "QToolButton{ border-style:solid; background-color: transparent;" "padding-left: 6px;" "padding-right: 6px;" "padding-top: 2px;" "padding-bottom: 2px;" "margin: 0px; }" "QToolButton:checked{ background-color: qconicalgradient(cx:0.15, cy:0.5, angle:0, stop:0 transparent, stop:0.3500 ") + highlight_back + QLatin1String(", stop:0.3700 palette(window), stop:0.6500 palette(window), stop:0.6700 ") + highlight_back + QLatin1String(", stop:1 transparent); }" "QToolButton:hover:!checked{ background-color: qlineargradient(x1:-2, y1:0, x2:1, y2:0, stop:0 ") + shadow + QLatin1String(",stop:1 transparent); }") ); break; } } void ChoqokTabBar::init_extra_widget(const QSize &size) { QWidget *widget; if (p->corners_hash.contains(Qt::TopLeftCorner)) { widget = p->corners_hash.value(Qt::TopLeftCorner); widget->move(0 , 0); } if (p->corners_hash.contains(Qt::TopRightCorner)) { widget = p->corners_hash.value(Qt::TopRightCorner); widget->move(size.width() - widget->width() , 0); } if (p->corners_hash.contains(Qt::BottomLeftCorner)) { widget = p->corners_hash.value(Qt::BottomLeftCorner); widget->move(0 , size.height() - widget->height()); } if (p->corners_hash.contains(Qt::BottomRightCorner)) { widget = p->corners_hash.value(Qt::BottomRightCorner); widget->move(size.width() - widget->width() , size.height() - widget->height()); } } void ChoqokTabBar::init_alongside_widget(const QSize &size) { if (!p->tab_alongside_widget) { return; } QWidget *widget = p->tab_alongside_widget; switch (static_cast(tabPosition())) { case North : widget->move(size.width() - widget->width() , 0); break; case South : widget->move(size.width() - widget->width() , size.height() - widget->height()); break; case West : widget->move(0 , size.height() - widget->height()); break; case East : widget->move(size.width() - widget->width() , size.height() - widget->height()); break; } } void ChoqokTabBar::resizeEvent(QResizeEvent *event) { QWidget::resizeEvent(event); init_extra_widget(event->size()); init_alongside_widget(event->size()); } void ChoqokTabBar::paintEvent(QPaintEvent *) { if (p->old_palette != palette()) { init_style(); } } void ChoqokTabBar::contextMenuRequest(const QPoint &) { const QPoint &global_point = QCursor::pos(); const QPoint &local_point = mapFromGlobal(global_point); QAction *action = p->toolbar->actionAt(local_point); if (action) { Q_EMIT contextMenu(global_point); Q_EMIT contextMenu(widget(p->actions_list.indexOf(action)) , global_point); return; } QAction north(i18n("Top") , this); QAction west(i18n("Left") , this); QAction east(i18n("Right") , this); QAction south(i18n("Bottom") , this); QAction size_s(i18n("Small") , this); QAction size_m(i18n("Medium") , this); QAction size_b(i18n("Big") , this); QAction styled(i18n("Styled Panel") , this); /*! ------------- Setting Up Datas --------------- */ north.setData(ChoqokTabBar::North); west.setData(ChoqokTabBar::West); east.setData(ChoqokTabBar::East); south.setData(ChoqokTabBar::South); size_s.setData(ICON_SMALL_SIZE); size_m.setData(ICON_MEDIUM_SIZE); size_b.setData(ICON_BIG_SIZE); /*! ------------------------------------------------ */ /*! ------------- Setting Up Actions --------------- */ north.setCheckable(true); west.setCheckable(true); east.setCheckable(true); south.setCheckable(true); size_s.setCheckable(true); size_m.setCheckable(true); size_b.setCheckable(true); styled.setCheckable(true); /*! ------------------------------------------------ */ /*! ------------- Setting Up Checks --------------- */ switch (static_cast(tabPosition())) { case ChoqokTabBar::North : north.setChecked(true); break; case ChoqokTabBar::South : south.setChecked(true); break; case ChoqokTabBar::West : west.setChecked(true); break; case ChoqokTabBar::East : east.setChecked(true); break; } if (iconSize() == QSize(ICON_SMALL_SIZE, ICON_SMALL_SIZE)) { size_s.setChecked(true); } else if (iconSize() == QSize(ICON_MEDIUM_SIZE, ICON_MEDIUM_SIZE)) { size_m.setChecked(true); } else if (iconSize() == QSize(ICON_BIG_SIZE, ICON_BIG_SIZE)) { size_b.setChecked(true); } styled.setChecked(styledTabBar()); /*! ------------------------------------------------ */ QMenu menu; menu.addAction(&north); menu.addAction(&west); menu.addAction(&east); //menu.addAction( &south ); menu.addSeparator(); menu.addAction(&size_s); menu.addAction(&size_m); menu.addAction(&size_b); menu.addSeparator(); menu.addAction(&styled); QAction *result = menu.exec(global_point); if (!result) { return; } else if (result == &styled) { setStyledTabBar(result->isChecked()); } else if (result == &size_s || result == &size_m || result == &size_b) { setIconSize(QSize(result->data().toInt() , result->data().toInt())); } else { setTabPosition(static_cast(result->data().toInt())); } } void ChoqokTabBar::widget_destroyed(QObject *obj) { removePage(static_cast(obj)); } ChoqokTabBar::~ChoqokTabBar() { Choqok::AppearanceSettings::setTabBarPosition(tabPosition()); Choqok::AppearanceSettings::setTabBarSize(iconSize().width()); Choqok::AppearanceSettings::setTabBarIsStyled(p->styled_tabbar); Choqok::AppearanceSettings::self()->save(); setLinkedTabBar(false); delete p; } } } diff --git a/libchoqok/ui/choqoktextedit.cpp b/libchoqok/ui/choqoktextedit.cpp index d1a0b102..3a5222c7 100644 --- a/libchoqok/ui/choqoktextedit.cpp +++ b/libchoqok/ui/choqoktextedit.cpp @@ -1,315 +1,316 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "choqoktextedit.h" #include #include #include #include #include #include #include #include #include #include "choqokbehaviorsettings.h" #include "libchoqokdebug.h" #include "shortenmanager.h" namespace Choqok { namespace UI { class TextEdit::Private { public: Private(uint charLmt) : langActions(new QMenu), charLimit(charLmt) {} QMenu *langActions; QMap langActionMap; uint charLimit; QString prevStr; QChar firstChar; QString curLang; }; TextEdit::TextEdit(uint charLimit /*= 0*/, QWidget *parent /*= 0*/) : KTextEdit(parent), d(new Private(charLimit)) { qCDebug(CHOQOK) << charLimit; - connect(this, SIGNAL(textChanged()), this, SLOT(updateRemainingCharsCount())); + connect(this, &TextEdit::textChanged, this, &TextEdit::updateRemainingCharsCount); setAcceptRichText(false); this->setToolTip(i18n("Note:
Ctrl+S to enable/disable auto spell checker.")); enableFindReplace(false); QFont counterF; counterF.setBold(true); counterF.setPointSize(10); lblRemainChar = new QLabel(this); lblRemainChar->resize(50, 50); lblRemainChar->setFont(counterF); QGridLayout *layout = new QGridLayout(this); layout->setRowStretch(0, 100); layout->setColumnStretch(5, 100); layout->setMargin(0); layout->setSpacing(0); layout->addWidget(lblRemainChar, 1, 0); this->setLayout(layout); setTabChangesFocus(true); settingsChanged(); - connect(BehaviorSettings::self(), SIGNAL(configChanged()), SLOT(settingsChanged())); + connect(BehaviorSettings::self(), &BehaviorSettings::configChanged, + this, &TextEdit::settingsChanged); QTimer::singleShot(1000, this, SLOT(setupSpeller())); - connect(this, SIGNAL(aboutToShowContextMenu(QMenu*)), - SLOT(slotAboutToShowContextMenu(QMenu*))); + connect(this, &TextEdit::aboutToShowContextMenu, this, + &TextEdit::slotAboutToShowContextMenu); } TextEdit::~TextEdit() { BehaviorSettings::setSpellerLanguage(d->curLang); d->langActions->deleteLater(); delete d; } void TextEdit::keyPressEvent(QKeyEvent *e) { if ((e->key() == Qt::Key_Return) || (e->key() == Qt::Key_Enter)) { if (e->modifiers() == Qt::ShiftModifier) { KTextEdit::keyPressEvent(e); } else { QString txt = toPlainText(); Q_EMIT returnPressed(txt); } e->accept(); } else if (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_S) { this->setCheckSpellingEnabled(!this->checkSpellingEnabled()); e->accept(); } else if (e->key() == Qt::Key_Escape) { if (!this->toPlainText().isEmpty()) { this->clear(); Q_EMIT cleared(); e->accept(); } else { KTextEdit::keyPressEvent(e); } } else { KTextEdit::keyPressEvent(e); } } void TextEdit::clear() { if (toPlainText().isEmpty()) { return; } else { undoableClear(); Q_EMIT cleared(); } } void TextEdit::undoableClear() { QTextCursor cursor = textCursor(); cursor.beginEditBlock(); cursor.movePosition(QTextCursor::Start); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.removeSelectedText(); cursor.endEditBlock(); } void TextEdit::insertFromMimeData(const QMimeData *source) { if (Choqok::BehaviorSettings::shortenOnPaste()) { KTextEdit::insertPlainText(ShortenManager::self()->parseText(source->text())); } else { KTextEdit::insertPlainText(source->text()); } } void TextEdit::updateRemainingCharsCount() { QString txt = this->toPlainText(); int count = txt.count(); if (count) { lblRemainChar->show(); if (d->charLimit) { int remain = d->charLimit - count; if (remain < 0) { lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: red;}")); } else if (remain < 30) { lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: rgb(242, 179, 19);}")); } else { lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: green;}")); } lblRemainChar->setText(QString::number(remain)); } else { lblRemainChar->setText(QString::number(count)); lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: blue;}")); } txt.remove(QRegExp(QLatin1String("@([^\\s\\W]+)"))); txt = txt.trimmed(); if (d->firstChar != txt[0]) { d->firstChar = txt[0]; txt.prepend(QLatin1Char(' ')); QTextBlockFormat f; f.setLayoutDirection((Qt::LayoutDirection) txt.isRightToLeft()); textCursor().mergeBlockFormat(f); } } else { lblRemainChar->hide(); } } void TextEdit::slotAboutToShowContextMenu(QMenu *menu) { if (menu) { qCDebug(CHOQOK); QAction *act = new QAction(i18n("Set spell check language"), menu); act->setMenu(d->langActions); menu->addAction(act); QAction *shorten = new QAction(i18nc("Replace URLs by a shortened URL", "Shorten URLs"), menu); - connect(shorten, SIGNAL(triggered(bool)), SLOT(shortenUrls())); + connect(shorten, &QAction::triggered, this, &TextEdit::shortenUrls); menu->addAction(shorten); } } void TextEdit::shortenUrls() { qCDebug(CHOQOK); QTextCursor cur = textCursor(); if (!cur.hasSelection()) { cur.select(QTextCursor::BlockUnderCursor); } QString shortened = ShortenManager::self()->parseText(cur.selectedText()); cur.removeSelectedText(); cur.insertText(shortened); setTextCursor(cur); } void TextEdit::slotChangeSpellerLanguage() { QAction *act = qobject_cast(sender()); if (act) { QString lang = act->data().toString(); setSpellCheckingLanguage(lang); d->langActionMap.value(d->curLang)->setChecked(false); d->curLang = lang; } } uint TextEdit::charLimit() { return d->charLimit; } QChar TextEdit::firstChar() { return d->firstChar; } void TextEdit::setFirstChar(const QChar &firstChar) { d->firstChar = firstChar; } void TextEdit::setCharLimit(uint charLimit /*= 0*/) { d->charLimit = charLimit; updateRemainingCharsCount(); } void TextEdit::setPlainText(const QString &text) { if (Choqok::BehaviorSettings::shortenOnPaste()) { KTextEdit::setPlainText(ShortenManager::self()->parseText(text)); } else { KTextEdit::setPlainText(text); } moveCursor(QTextCursor::End); setEnabled(true); } void TextEdit::setText(const QString &text) { KTextEdit::setPlainText(text); moveCursor(QTextCursor::End); setEnabled(true); } void TextEdit::prependText(const QString &text) { QString tmp = text; tmp.append(QLatin1Char(' ') + toPlainText()); setPlainText(tmp); } void TextEdit::appendText(const QString &text) { QString tmp = toPlainText(); if (tmp.isEmpty()) { tmp = text + QLatin1Char(' '); } else { tmp.append(QLatin1Char(' ') + text); } setPlainText(tmp); } void TextEdit::settingsChanged() { setCheckSpellingEnabled(BehaviorSettings::enableSpellChecker()); } void TextEdit::setupSpeller() { BehaviorSettings::self()->load(); d->curLang = BehaviorSettings::spellerLanguage(); Sonnet::Speller s; if (d->curLang.isEmpty()) { d->curLang = s.defaultLanguage(); } qCDebug(CHOQOK) << "Current LANG:" << d->curLang; for (const QString &dict: s.availableDictionaries().keys()) { const QString value = s.availableDictionaries().value(dict); QAction *act = new QAction(dict, d->langActions); act->setData(value); act->setCheckable(true); if (d->curLang == value) { act->setChecked(true); } - connect(act, SIGNAL(triggered(bool)), SLOT(slotChangeSpellerLanguage())); + connect(act, &QAction::triggered, this, &TextEdit::slotChangeSpellerLanguage); d->langActions->addAction(act); d->langActionMap.insert(value, act); } } QSize TextEdit::minimumSizeHint() const { const QSize size = KTextEdit::minimumSizeHint(); return QSize(size.width(), qMax(fontMetrics().height() * 3, size.height())); } } } diff --git a/libchoqok/ui/composerwidget.cpp b/libchoqok/ui/composerwidget.cpp index b897a5c3..3d0c0fbe 100644 --- a/libchoqok/ui/composerwidget.cpp +++ b/libchoqok/ui/composerwidget.cpp @@ -1,255 +1,249 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "composerwidget.h" #include #include #include #include #include "account.h" #include "choqoktextedit.h" #include "libchoqokdebug.h" #include "microblog.h" #include "notifymanager.h" #include "shortenmanager.h" namespace Choqok { namespace UI { class ComposerWidget::Private { public: Private(Account *account) : editor(0), currentAccount(account), postToSubmit(0) {} QPointer editor; Account *currentAccount; Choqok::Post *postToSubmit; QWidget *editorContainer; QPointer replyToUsernameLabel; QPointer btnCancelReply; }; ComposerWidget::ComposerWidget(Choqok::Account *account, QWidget *parent /*= 0*/) : QWidget(parent), btnAbort(0), d(new Private(account)) { QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); d->editorContainer = new QWidget(this); QGridLayout *internalLayout = new QGridLayout; internalLayout->setContentsMargins(0, 0, 0, 0); d->editorContainer->setLayout(internalLayout); layout->addWidget(editorContainer()); setEditor(new TextEdit(account->postCharLimit(), this)); d->replyToUsernameLabel = new QLabel(editorContainer()); d->btnCancelReply = new QPushButton(editorContainer()); d->btnCancelReply->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel"))); d->btnCancelReply->setToolTip(i18n("Discard Reply")); d->btnCancelReply->setMaximumWidth(d->btnCancelReply->height()); - connect(d->btnCancelReply, SIGNAL(clicked(bool)), SLOT(editorCleared())); + connect(d->btnCancelReply, &QPushButton::clicked, this, &ComposerWidget::editorCleared); internalLayout->addWidget(d->replyToUsernameLabel, 2, 0); internalLayout->addWidget(d->btnCancelReply, 2, 1); d->btnCancelReply->hide(); d->replyToUsernameLabel->hide(); } ComposerWidget::~ComposerWidget() { delete d; } void ComposerWidget::setEditor(TextEdit *editor) { qCDebug(CHOQOK); if (d->editor) { d->editor->deleteLater(); } d->editor = editor; qCDebug(CHOQOK); if (d->editor) { QGridLayout *internalLayout = qobject_cast(d->editorContainer->layout()); internalLayout->addWidget(d->editor, 0, 0); - connect(d->editor, SIGNAL(returnPressed(QString)), SLOT(submitPost(QString))); - connect(d->editor, SIGNAL(textChanged()), SLOT(editorTextChanged())); - connect(d->editor, SIGNAL(cleared()), SLOT(editorCleared())); + connect(d->editor, &TextEdit::returnPressed, this, &ComposerWidget::submitPost); + connect(d->editor, &TextEdit::textChanged, this, &ComposerWidget::editorTextChanged); + connect(d->editor, &TextEdit::cleared, this, &ComposerWidget::editorCleared); editorTextChanged(); } else { qCDebug(CHOQOK) << "Editor is NULL!"; } } void ComposerWidget::setText(const QString &text, const QString &replyToId, const QString &replyToUsername) { d->editor->prependText(text); this->replyToId = replyToId; this->replyToUsername = replyToUsername; if (!replyToUsername.isEmpty()) { d->replyToUsernameLabel->setText(i18n("Replying to %1", replyToUsername)); d->btnCancelReply->show(); d->replyToUsernameLabel->show(); } d->editor->setFocus(); } void ComposerWidget::submitPost(const QString &txt) { qCDebug(CHOQOK); editorContainer()->setEnabled(false); QString text = txt; if (currentAccount()->postCharLimit() && text.size() > (int)currentAccount()->postCharLimit()) { text = Choqok::ShortenManager::self()->parseText(text); } delete d->postToSubmit; d->postToSubmit = new Choqok::Post; d->postToSubmit->content = text; if (!replyToId.isEmpty()) { d->postToSubmit->replyToPostId = replyToId; } - connect(d->currentAccount->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - SLOT(slotPostSubmited(Choqok::Account*,Choqok::Post*))); - connect(d->currentAccount->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + connect(d->currentAccount->microblog(), &MicroBlog::postCreated, + this, &ComposerWidget::slotPostSubmited); + connect(d->currentAccount->microblog(), &MicroBlog::errorPost, + this, &ComposerWidget::slotErrorPost); btnAbort = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("Abort"), this); layout()->addWidget(btnAbort); - connect(btnAbort, SIGNAL(clicked(bool)), SLOT(abort())); + connect(btnAbort, &QPushButton::clicked, this, &ComposerWidget::abort); currentAccount()->microblog()->createPost(currentAccount(), d->postToSubmit); } void ComposerWidget::slotPostSubmited(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (currentAccount() == theAccount && post == d->postToSubmit) { qCDebug(CHOQOK) << "Accepted"; - disconnect(d->currentAccount->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotPostSubmited(Choqok::Account*,Choqok::Post*))); - disconnect(d->currentAccount->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + disconnect(d->currentAccount->microblog(), &MicroBlog::postCreated, + this, &ComposerWidget::slotPostSubmited); + disconnect(d->currentAccount->microblog(), &MicroBlog::errorPost, + this, &ComposerWidget::slotErrorPost); if (btnAbort) { btnAbort->deleteLater(); } d->editor->clear(); editorCleared(); editorContainer()->setEnabled(true); delete d->postToSubmit; d->postToSubmit = nullptr; currentAccount()->microblog()->updateTimelines(currentAccount()); } } void ComposerWidget::slotErrorPost(Account *theAccount, Post *post) { qCDebug(CHOQOK); if (theAccount == d->currentAccount && post == d->postToSubmit) { qCDebug(CHOQOK); - disconnect(d->currentAccount->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotPostSubmited(Choqok::Account*,Choqok::Post*))); - disconnect(d->currentAccount->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + disconnect(d->currentAccount->microblog(), &MicroBlog::postCreated, + this, &ComposerWidget::slotPostSubmited); + disconnect(d->currentAccount->microblog(), &MicroBlog::errorPost, + this, &ComposerWidget::slotErrorPost); if (btnAbort) { btnAbort->deleteLater(); } editorContainer()->setEnabled(true); editor()->setFocus(); } } void ComposerWidget::editorTextChanged() { if (d->editor->toPlainText().length()) { d->editor->setMaximumHeight(qMax(d->editor->fontMetrics().height() * 3, 80)); d->editor->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); } else { d->editor->setMaximumHeight(qMax(d->editor->fontMetrics().height(), 30)); d->editor->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } } TextEdit *ComposerWidget::editor() { return d->editor; } QWidget *ComposerWidget::editorContainer() { return d->editorContainer; } Post *ComposerWidget::postToSubmit() { return d->postToSubmit; } void ComposerWidget::setPostToSubmit(Post *post) { delete d->postToSubmit; d->postToSubmit = post; } QPointer< QPushButton > ComposerWidget::btnCancelReply() { return d->btnCancelReply; } Account *ComposerWidget::currentAccount() { return d->currentAccount; } QPointer< QLabel > ComposerWidget::replyToUsernameLabel() { return d->replyToUsernameLabel; } void ComposerWidget::editorCleared() { replyToId.clear(); replyToUsername.clear(); d->btnCancelReply->hide(); d->replyToUsernameLabel->hide(); } void ComposerWidget::abort() { if (btnAbort) { btnAbort->deleteLater(); } editorContainer()->setEnabled(true); currentAccount()->microblog()->abortCreatePost(currentAccount(), d->postToSubmit); editor()->setFocus(); } } } diff --git a/libchoqok/ui/microblogwidget.cpp b/libchoqok/ui/microblogwidget.cpp index 42d03e4b..9df2fa9f 100644 --- a/libchoqok/ui/microblogwidget.cpp +++ b/libchoqok/ui/microblogwidget.cpp @@ -1,465 +1,455 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "microblogwidget.h" #include #include #include #include #include #include #include #include #include #include #include "account.h" #include "choqokappearancesettings.h" #include "choqoktextedit.h" #include "choqokuiglobal.h" #include "composerwidget.h" #include "libchoqokdebug.h" #include "notifymanager.h" #include "timelinewidget.h" namespace Choqok { namespace UI { QIcon addNumToIcon(const QIcon &big , int number , const QSize &result_size , const QPalette &palette) { QIcon result; QList mods; mods << QIcon::Active /*<< QIcon::Disabled << QIcon::Selected*/; for (const QIcon::Mode &m: mods) { QPixmap pixmap = big.pixmap(result_size); QPainter painter(&pixmap); QFont font; font.setWeight(result_size.height() / 2); font.setBold(true); font.setItalic(true); painter.setFont(font); QString numberStr = QString::number(number); int textWidth = painter.fontMetrics().width(numberStr) + 6; if (textWidth < result_size.width() / 2) { textWidth = result_size.width() / 2; } QRect rct(result_size.width() - textWidth , result_size.width() / 2 , textWidth , result_size.height() / 2); QPointF center(rct.x() + rct.width() / 2 , rct.y() + rct.height() / 2); QPainterPath cyrcle_path; cyrcle_path.moveTo(center); cyrcle_path.arcTo(rct, 0, 360); painter.setRenderHint(QPainter::Antialiasing); painter.fillPath(cyrcle_path , palette.color(QPalette::Active , QPalette::Window)); painter.setPen(palette.color(QPalette::Active , QPalette::Text)); painter.drawText(rct , Qt::AlignHCenter | Qt::AlignVCenter , QString::number(number)); result.addPixmap(pixmap , m); } return result; } class MicroBlogWidget::Private { public: Private(Account *acc) : account(acc), blog(acc->microblog()), composer(0), btnMarkAllAsRead(0) { } Account *account; MicroBlog *blog; QPointer composer; QMap timelines; Choqok::UI::ChoqokTabBar *timelinesTabWidget; QLabel *latestUpdate; QPushButton *btnMarkAllAsRead; QHBoxLayout *toolbar; QFrame *toolbar_widget; }; MicroBlogWidget::MicroBlogWidget(Account *account, QWidget *parent) : QWidget(parent), d(new Private(account)) { qCDebug(CHOQOK); - connect(d->blog, SIGNAL(timelineDataReceived(Choqok::Account*,QString,QList)), - this, SLOT(newTimelineDataRecieved(Choqok::Account*,QString,QList))); - connect(d->blog, SIGNAL(error(Choqok::Account *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(error(Choqok::Account *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel))); - connect(d->blog, SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, - Choqok::MicroBlog::ErrorType, QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel))); + connect(d->blog, &MicroBlog::timelineDataReceived, this, &MicroBlogWidget::newTimelineDataRecieved); + connect(d->blog, &MicroBlog::error, this, &MicroBlogWidget::error); + connect(d->blog, &MicroBlog::errorPost, this, &MicroBlogWidget::errorPost); } Account *MicroBlogWidget::currentAccount() const { return d->account; } void MicroBlogWidget::initUi() { d->toolbar_widget = new QFrame(); d->toolbar_widget->setFrameShape(QFrame::StyledPanel); d->toolbar_widget->setFrameShadow(QFrame::Sunken); QVBoxLayout *layout = new QVBoxLayout(this); QVBoxLayout *toolbar_layout = new QVBoxLayout(d->toolbar_widget); toolbar_layout->addLayout(createToolbar()); d->timelinesTabWidget = new Choqok::UI::ChoqokTabBar(this); d->timelinesTabWidget->setLinkedTabBar(true); d->timelinesTabWidget->setTabCloseActivatePrevious(true); d->timelinesTabWidget->setExtraWidget(d->toolbar_widget , Choqok::UI::ChoqokTabBar::Top); if (!d->account->isReadOnly()) { setComposerWidget(d->blog->createComposerWidget(currentAccount(), this)); } layout->addWidget(d->timelinesTabWidget); this->layout()->setContentsMargins(0, 0, 0, 0); - connect(currentAccount(), SIGNAL(modified(Choqok::Account*)), SLOT(slotAccountModified(Choqok::Account*))); + connect(currentAccount(), &Account::modified, this, &MicroBlogWidget::slotAccountModified); initTimelines(); } void MicroBlogWidget::setComposerWidget(ComposerWidget *widget) { if (d->composer) { d->composer->deleteLater(); } if (!widget) { d->composer = nullptr; return; } d->composer = widget; d->composer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); qobject_cast(d->toolbar_widget->layout())->insertWidget(1, d->composer); for (TimelineWidget *mbw: d->timelines) { connect(mbw, SIGNAL(forwardResendPost(QString)), d->composer, SLOT(setText(QString))); - connect(mbw, SIGNAL(forwardReply(QString,QString,QString)), d->composer, SLOT(setText(QString,QString,QString))); + connect(mbw, &TimelineWidget::forwardReply, d->composer, &ComposerWidget::setText); } } MicroBlogWidget::~MicroBlogWidget() { qCDebug(CHOQOK); delete d; } TimelineWidget *MicroBlogWidget::currentTimeline() { return qobject_cast(d->timelinesTabWidget->currentWidget()); } uint MicroBlogWidget::unreadCount() const { uint sum = 0; for (TimelineWidget *wd: d->timelines) { sum += wd->unreadCount(); } return sum; } void MicroBlogWidget::settingsChanged() { for (TimelineWidget *wd: d->timelines) { wd->settingsChanged(); } } void MicroBlogWidget::updateTimelines() { qCDebug(CHOQOK) << d->account->alias(); d->account->microblog()->updateTimelines(currentAccount()); } void MicroBlogWidget::removeOldPosts() { for (TimelineWidget *wd: d->timelines) { wd->removeOldPosts(); } } void MicroBlogWidget::newTimelineDataRecieved(Choqok::Account *theAccount, const QString &type, QList< Choqok::Post * > data) { if (theAccount != currentAccount()) { return; } qCDebug(CHOQOK) << d->account->alias() << ":" << type; d->latestUpdate->setText(QTime::currentTime().toString()); if (d->timelines.contains(type)) { d->timelines.value(type)->addNewPosts(data); } else { if (TimelineWidget *wd = addTimelineWidgetToUi(type)) { wd->addNewPosts(data); } } } void MicroBlogWidget::initTimelines() { qCDebug(CHOQOK); for (const QString &timeline: d->account->timelineNames()) { addTimelineWidgetToUi(timeline); } // qCDebug(CHOQOK)<<"========== Emiting loaded()"; Q_EMIT loaded(); } TimelineWidget *MicroBlogWidget::addTimelineWidgetToUi(const QString &name) { TimelineWidget *mbw = d->blog->createTimelineWidget(d->account, name, this); if (mbw) { Choqok::TimelineInfo *info = currentAccount()->microblog()->timelineInfo(name); d->timelines.insert(name, mbw); d->timelinesTabWidget->addTab(mbw, info->name); d->timelinesTabWidget->setTabIcon(d->timelinesTabWidget->indexOf(mbw), QIcon::fromTheme(info->icon)); - connect(mbw, SIGNAL(updateUnreadCount(int)), - this, SLOT(slotUpdateUnreadCount(int))); + connect(mbw, SIGNAL(updateUnreadCount(int)), this, SLOT(slotUpdateUnreadCount(int))); if (d->composer) { - connect(mbw, SIGNAL(forwardResendPost(QString)), - d->composer, SLOT(setText(QString))); - connect(mbw, SIGNAL(forwardReply(QString,QString,QString)), - d->composer, SLOT(setText(QString,QString,QString))); + connect(mbw, SIGNAL(forwardResendPost(QString)), d->composer, SLOT(setText(QString))); + connect(mbw, &TimelineWidget::forwardReply, d->composer, &ComposerWidget::setText); } slotUpdateUnreadCount(mbw->unreadCount(), mbw); } else { qCDebug(CHOQOK) << "Cannot Create a new TimelineWidget for timeline " << name; return nullptr; } if (d->timelinesTabWidget->count() == 1) { d->timelinesTabWidget->setTabBarHidden(true); } else { d->timelinesTabWidget->setTabBarHidden(false); } return mbw; } void MicroBlogWidget::slotUpdateUnreadCount(int change, Choqok::UI::TimelineWidget *widget) { qCDebug(CHOQOK) << change; int sum = 0; for (TimelineWidget *mbw: d->timelines) { sum += mbw->unreadCount(); } if (change != 0) { Q_EMIT updateUnreadCount(change, sum); } if (sum > 0) { if (!d->btnMarkAllAsRead) { d->btnMarkAllAsRead = new QPushButton(this); d->btnMarkAllAsRead->setIcon(QIcon::fromTheme(QLatin1String("mail-mark-read"))); d->btnMarkAllAsRead->setIconSize(QSize(14, 14)); d->btnMarkAllAsRead->setToolTip(i18n("Mark all timelines as read")); d->btnMarkAllAsRead->setMaximumWidth(d->btnMarkAllAsRead->height()); - connect(d->btnMarkAllAsRead, SIGNAL(clicked(bool)), SLOT(markAllAsRead())); + connect(d->btnMarkAllAsRead, &QPushButton::clicked, this, &MicroBlogWidget::markAllAsRead); d->toolbar->insertWidget(1, d->btnMarkAllAsRead); } } else { d->btnMarkAllAsRead->deleteLater(); d->btnMarkAllAsRead = nullptr; } TimelineWidget *wd = qobject_cast(sender()); if (!wd) { wd = widget; } if (wd) { qCDebug(CHOQOK) << wd->unreadCount(); int tabIndex = d->timelinesTabWidget->indexOf(wd); if (tabIndex == -1) { return; } if (wd->unreadCount() > 0) { d->timelinesTabWidget->setTabIcon(tabIndex , addNumToIcon(timelinesTabWidget()->tabIcon(tabIndex) , wd->unreadCount() , QSize(40, 40) , palette())); d->timelinesTabWidget->setTabText(tabIndex, wd->timelineInfoName() + QStringLiteral("(%1)").arg(wd->unreadCount())); } else { if (!wd->timelineIconName().isEmpty()) { d->timelinesTabWidget->setTabIcon(tabIndex , QIcon::fromTheme(wd->timelineIconName())); } else { d->timelinesTabWidget->setTabIcon(tabIndex , wd->timelineIcon()); } d->timelinesTabWidget->setTabText(tabIndex, wd->timelineInfoName()); } } } void MicroBlogWidget::markAllAsRead() { if (d->btnMarkAllAsRead) { d->btnMarkAllAsRead->deleteLater(); d->btnMarkAllAsRead = nullptr; } for (TimelineWidget *wd: d->timelines) { wd->markAllAsRead(); int tabIndex = d->timelinesTabWidget->indexOf(wd); if (tabIndex == -1) { continue; } d->timelinesTabWidget->setTabText(tabIndex, wd->timelineInfoName()); } } ComposerWidget *MicroBlogWidget::composer() { return d->composer; } QMap< QString, TimelineWidget * > &MicroBlogWidget::timelines() { return d->timelines; } Choqok::UI::ChoqokTabBar *MicroBlogWidget::timelinesTabWidget() { return d->timelinesTabWidget; } void MicroBlogWidget::error(Choqok::Account *theAccount, MicroBlog::ErrorType errorType, const QString &errorMsg, MicroBlog::ErrorLevel level) { if (theAccount == d->account) { switch (level) { case MicroBlog::Critical: KMessageBox::error(Choqok::UI::Global::mainWindow(), errorMsg, MicroBlog::errorString(errorType)); break; case MicroBlog::Normal: NotifyManager::error(errorMsg, MicroBlog::errorString(errorType)); break; default: // emit showStatusMessage(errorMsg); if (Choqok::UI::Global::mainWindow()->statusBar()) { Choqok::UI::Global::mainWindow()->statusBar()->showMessage(errorMsg); } break; }; } } void MicroBlogWidget::errorPost(Choqok::Account *theAccount, Choqok::Post *, MicroBlog::ErrorType errorType, const QString &errorMsg, MicroBlog::ErrorLevel level) { if (theAccount == d->account) { switch (level) { case MicroBlog::Critical: KMessageBox::error(Choqok::UI::Global::mainWindow(), errorMsg, MicroBlog::errorString(errorType)); break; case MicroBlog::Normal: NotifyManager::error(errorMsg, MicroBlog::errorString(errorType)); break; default: // emit showStatusMessage(errorMsg); if (Choqok::UI::Global::mainWindow()->statusBar()) { Choqok::UI::Global::mainWindow()->statusBar()->showMessage(errorMsg); } break; }; } } QLayout *MicroBlogWidget::createToolbar() { d->toolbar = new QHBoxLayout; QPushButton *btnActions = new QPushButton(i18n("More"), this); QLabel *lblLatestUpdate = new QLabel(i18n("Latest update:"), this); lblLatestUpdate->setAlignment(Qt::AlignRight | Qt::AlignVCenter); d->latestUpdate = new QLabel(QTime::currentTime().toString(), this); QFont fnt = lblLatestUpdate->font(); fnt.setPointSize(fnt.pointSize() - 1); lblLatestUpdate->setFont(fnt); fnt.setBold(true); d->latestUpdate->setFont(fnt); btnActions->setMenu(d->account->microblog()->createActionsMenu(d->account)); d->toolbar->addWidget(btnActions); d->toolbar->addSpacerItem(new QSpacerItem(1, 10, QSizePolicy::Expanding)); d->toolbar->addWidget(lblLatestUpdate); d->toolbar->addWidget(d->latestUpdate); return d->toolbar; } void MicroBlogWidget::slotAbortAllJobs() { currentAccount()->microblog()->abortAllJobs(currentAccount()); composer()->abort(); } void MicroBlogWidget::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Escape && composer()) { composer()->abort(); } QWidget::keyPressEvent(e); } void MicroBlogWidget::setFocus() { if (composer()) { composer()->editor()->setFocus(Qt::OtherFocusReason); } else { QWidget::setFocus(); } } void MicroBlogWidget::slotAccountModified(Account *theAccount) { if (theAccount == currentAccount()) { if (theAccount->isReadOnly()) { if (composer()) { setComposerWidget(nullptr); } } else if (!composer()) { setComposerWidget(theAccount->microblog()->createComposerWidget(theAccount, this)); } int sum = 0; for (TimelineWidget *mbw: d->timelines) { sum += mbw->unreadCount(); } Q_EMIT updateUnreadCount(0, sum); } } QLabel *MicroBlogWidget::latestUpdate() { return d->latestUpdate; } } } diff --git a/libchoqok/ui/postwidget.cpp b/libchoqok/ui/postwidget.cpp index 30bf3540..a105d728 100644 --- a/libchoqok/ui/postwidget.cpp +++ b/libchoqok/ui/postwidget.cpp @@ -1,726 +1,719 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "postwidget.h" #include #include #include #include #include #include #include "choqokappearancesettings.h" #include "choqokbehaviorsettings.h" #include "choqoktools.h" #include "choqokuiglobal.h" #include "libchoqokdebug.h" #include "mediamanager.h" #include "quickpost.h" #include "timelinewidget.h" #include "textbrowser.h" #include "urlutils.h" static const int _15SECS = 15000; static const int _MINUTE = 60000; static const int _HOUR = 60 * _MINUTE; using namespace Choqok; using namespace Choqok::UI; class PostWidget::Private { public: Private(Account *account, Choqok::Post *post) : mCurrentPost(post), mCurrentAccount(account), dir(QLatin1String("ltr")), timeline(0) { mCurrentPost->owners++; if (!mCurrentPost->media.isEmpty()) { imageUrl = mCurrentPost->media; } } QGridLayout *buttonsLayout; QMap mUiButtons; // Post *mCurrentPost; Account *mCurrentAccount; // bool mRead; QTimer mTimer; //BEGIN UI contents: QString mSign; QString mContent; QString mProfileImage; QString mImage; QUrl imageUrl; QString dir; QPixmap originalImage; QString extraContents; //END UI contents; QStringList detectedUrls; TimelineWidget *timeline; static const QLatin1String resourceImageUrl; }; const QString mImageTemplate(QLatin1String("
")); const QLatin1String PostWidget::Private::resourceImageUrl("img://postImage"); const QString PostWidget::baseTextTemplate(QLatin1String("%6%5
%1

%2

%3
")); const QString PostWidget::baseStyle(QLatin1String("QTextBrowser {border: 1px solid rgb(150,150,150);\ border-radius:5px; color:%1; background-color:%2; %3}\ QPushButton{border:0px} QPushButton::menu-indicator{image:none;}")); const QString PostWidget::hrefTemplate(QLatin1String("%2")); const QRegExp PostWidget::dirRegExp(QLatin1String("(RT|RD)|(@([^\\s\\W]+))|(#([^\\s\\W]+))|(!([^\\s\\W]+))")); QString PostWidget::readStyle; QString PostWidget::unreadStyle; QString PostWidget::ownStyle; const QString PostWidget::webIconText(QLatin1String("☛")); PostWidget::PostWidget(Account *account, Choqok::Post *post, QWidget *parent/* = 0*/) : QWidget(parent), _mainWidget(new TextBrowser(this)), d(new Private(account, post)) { setAttribute(Qt::WA_DeleteOnClose); _mainWidget->setFrameShape(QFrame::NoFrame); if (isOwnPost()) { d->mCurrentPost->isRead = true; } d->mTimer.start(_MINUTE); - connect(&d->mTimer, SIGNAL(timeout()), this, SLOT(updateUi())); - connect(_mainWidget, SIGNAL(clicked(QMouseEvent*)), SLOT(mousePressEvent(QMouseEvent*))); - connect(_mainWidget, SIGNAL(anchorClicked(QUrl)), this, SLOT(checkAnchor(QUrl))); + connect(&d->mTimer, &QTimer::timeout, this, &PostWidget::updateUi); + connect(_mainWidget, &TextBrowser::clicked, this, &PostWidget::mousePressEvent); + connect(_mainWidget, &TextBrowser::anchorClicked, this, &PostWidget::checkAnchor); d->timeline = qobject_cast(parent); setHeight(); } void PostWidget::checkAnchor(const QUrl &url) { if (url.scheme() == QLatin1String("choqok")) { if (url.host() == QLatin1String("showoriginalpost")) { setContent(prepareStatus(currentPost()->content).replace(QLatin1String("mCurrentPost->owners < 2) { delete d->mCurrentPost; } else { d->mCurrentPost->owners--; } delete d; } Account *PostWidget::currentAccount() { return d->mCurrentAccount; } QString PostWidget::generateSign() { QString ss = QStringLiteral("%1 - ").arg(getUsernameHyperlink(d->mCurrentPost->author)); QDateTime time; if (d->mCurrentPost->repeatedDateTime.isNull()) { time = d->mCurrentPost->creationDateTime; } else { time = d->mCurrentPost->repeatedDateTime; } ss += QStringLiteral("%3").arg(d->mCurrentPost->link.toDisplayString()) .arg(time.toString(Qt::DefaultLocaleLongDate)).arg(formatDateTime(time)); if (!d->mCurrentPost->source.isEmpty()) { ss += QLatin1String(" - ") + d->mCurrentPost->source; } return ss; } QString PostWidget::getUsernameHyperlink(const Choqok::User &user) const { return QStringLiteral("%3") .arg(d->mCurrentAccount->microblog()->profileUrl(d->mCurrentAccount, user.userName).toDisplayString()) .arg(user.description.isEmpty() ? user.realName : user.description) .arg(user.userName); } void PostWidget::setupUi() { setLayout(new QVBoxLayout); layout()->setMargin(0); layout()->setContentsMargins(0, 0, 0, 0); layout()->addWidget(_mainWidget); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); _mainWidget->setFocusProxy(this); d->buttonsLayout = new QGridLayout(_mainWidget); d->buttonsLayout->setRowStretch(0, 100); d->buttonsLayout->setColumnStretch(5, 100); d->buttonsLayout->setMargin(0); d->buttonsLayout->setSpacing(0); _mainWidget->setLayout(d->buttonsLayout); - connect(_mainWidget, SIGNAL(textChanged()), this, SLOT(setHeight())); + connect(_mainWidget, &TextBrowser::textChanged, this, &PostWidget::setHeight); } void PostWidget::initUi() { setupUi(); _mainWidget->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("img://profileImage")), MediaManager::self()->defaultImage()); if (isRemoveAvailable()) { QPushButton *btnRemove = addButton(QLatin1String("btnRemove"), i18nc("@info:tooltip", "Remove"), QLatin1String("edit-delete")); - connect(btnRemove, SIGNAL(clicked(bool)), SLOT(removeCurrentPost())); + connect(btnRemove, &QPushButton::clicked, this, &PostWidget::removeCurrentPost); } if (isResendAvailable()) { QPushButton *btnResend = addButton(QLatin1String("btnResend"), i18nc("@info:tooltip", "ReSend"), QLatin1String("retweet")); - connect(btnResend, SIGNAL(clicked(bool)), SLOT(slotResendPost())); + connect(btnResend, &QPushButton::clicked, this, &PostWidget::slotResendPost); } d->mProfileImage = QLatin1String("mCurrentPost->author.realName + QLatin1String("\" width=\"48\" height=\"48\" />"); d->mContent = prepareStatus(d->mCurrentPost->content); d->mSign = generateSign(); setupAvatar(); fetchImage(); d->dir = getDirection(d->mCurrentPost->content); setUiStyle(); d->mContent.replace(QLatin1String("mContent.replace(QLatin1String("\n"), QLatin1String("
")); d->extraContents.replace(QLatin1String("
mSign.replace(QLatin1String("setHtml(baseTextTemplate.arg( d->mProfileImage, /*1*/ d->mContent, /*2*/ d->mSign, /*3*/ d->dir, /*4*/ d->mImage, /*5*/ d->extraContents /*6*/ )); } void PostWidget::setStyle(const QColor &color, const QColor &back, const QColor &read, const QColor &readBack, const QColor &own, const QColor &ownBack, const QFont &font) { QString fntStr = QLatin1String("font-family:\"") + font.family() + QLatin1String("\"; font-size:") + QString::number(font.pointSize()) + QLatin1String("pt;"); fntStr += (font.bold() ? QLatin1String(" font-weight:bold;") : QString()) + (font.italic() ? QLatin1String(" font-style:italic;") : QString()); unreadStyle = baseStyle.arg(getColorString(color), getColorString(back), fntStr); readStyle = baseStyle.arg(getColorString(read), getColorString(readBack), fntStr); ownStyle = baseStyle.arg(getColorString(own), getColorString(ownBack), fntStr); } QPushButton *PostWidget::addButton(const QString &objName, const QString &toolTip, const QString &icon) { return addButton(objName, toolTip, QIcon::fromTheme(icon)); } QPushButton *PostWidget::addButton(const QString &objName, const QString &toolTip, const QIcon &icon) { QPushButton *button = new QPushButton(icon, QString(), _mainWidget); button->setObjectName(objName); button->setToolTip(toolTip); button->setIconSize(QSize(16, 16)); button->setMinimumSize(QSize(20, 20)); button->setMaximumSize(QSize(20, 20)); button->setFlat(true); button->setVisible(false); button->setCursor(Qt::PointingHandCursor); d->mUiButtons.insert(objName, button); d->buttonsLayout->addWidget(button, 1, d->mUiButtons.count()); return button; } Post *PostWidget::currentPost() const { return d->mCurrentPost; } void PostWidget::setCurrentPost(Post *post) { d->mCurrentPost = post; } void PostWidget::setRead(bool read/* = true*/) { if (!read && !currentPost()->isRead && currentAccount()->username().compare(currentPost()->author.userName, Qt::CaseInsensitive) == 0) { d->mCurrentPost->isRead = true; ///Always Set own posts as read. setUiStyle(); } else if (currentPost()->isRead != read) { d->mCurrentPost->isRead = read; setUiStyle(); } } void PostWidget::setReadWithSignal() { if (!isRead()) { setRead(); Q_EMIT postReaded(); } } bool PostWidget::isRead() const { return currentPost()->isRead; } void PostWidget::setUiStyle() { if (isOwnPost()) { setStyleSheet(ownStyle); } else { if (currentPost()->isRead) { setStyleSheet(readStyle); } else { setStyleSheet(unreadStyle); } } setHeight(); } bool PostWidget::isOwnPost() { return currentAccount()->username().compare(currentPost()->author.userName, Qt::CaseInsensitive) == 0; } void PostWidget::setHeight() { _mainWidget->document()->setTextWidth(width() - 2); int h = _mainWidget->document()->size().toSize().height() + 2; setFixedHeight(h); } void PostWidget::closeEvent(QCloseEvent *event) { clearFocus(); if (!isRead()) { setReadWithSignal(); } Q_EMIT aboutClosing(currentPost()->postId, this); event->accept(); } void PostWidget::mousePressEvent(QMouseEvent *ev) { if (!isRead()) { setReadWithSignal(); } QWidget::mousePressEvent(ev); } void PostWidget::resizeEvent(QResizeEvent *event) { updatePostImage( event->size().width() ); setHeight(); updateUi(); QWidget::resizeEvent(event); } void PostWidget::enterEvent(QEvent *event) { for (QPushButton *btn: buttons()) { if (btn) { //A crash happens here :/ btn->show(); } } QWidget::enterEvent(event); } void PostWidget::leaveEvent(QEvent *event) { for (QPushButton *btn: buttons()) { if (btn) { btn->hide(); } } QWidget::enterEvent(event); } void PostWidget::updatePostImage(int width) { if ( !d->originalImage.isNull() ) { // TODO: Find a way to calculate the difference we need to subtract. width -= 76; QPixmap newPixmap = d->originalImage.scaledToWidth(width, Qt::SmoothTransformation); auto newW = newPixmap.width(); auto newH = newPixmap.height(); auto origW = d->originalImage.width(); auto origH = d->originalImage.height(); const QUrl url(d->resourceImageUrl); // only use scaled image if it's smaller than the original one if (newW <= origW && newH <= origH) { // never scale up d->mImage = mImageTemplate.arg(QString::number(newW), QString::number(newH), d->resourceImageUrl); _mainWidget->document()->addResource(QTextDocument::ImageResource, url, newPixmap); } else { d->mImage = mImageTemplate.arg(QString::number(origW), QString::number(origH), d->resourceImageUrl); _mainWidget->document()->addResource(QTextDocument::ImageResource, url, d->originalImage); } } } QString PostWidget::prepareStatus(const QString &txt) { QString text = removeTags(txt); d->detectedUrls = UrlUtils::detectUrls(text); for (const QString &url: d->detectedUrls) { QString httpUrl(url); if (!httpUrl.startsWith(QLatin1String("http"), Qt::CaseInsensitive) && !httpUrl.startsWith(QLatin1String("ftp"), Qt::CaseInsensitive)) { httpUrl.prepend(QLatin1String("http://")); text.replace(url, httpUrl); } text.replace(url, hrefTemplate.arg(httpUrl, url)); } text = UrlUtils::detectEmails(text); if (AppearanceSettings::isEmoticonsEnabled()) { text = MediaManager::self()->parseEmoticons(text); } return text; } QString PostWidget::removeTags(const QString &text) const { QString txt(text); txt.replace(QLatin1Char('<'), QLatin1String("<")); txt.replace(QLatin1Char('>'), QLatin1String(">")); return txt; } QLatin1String PostWidget::getDirection(QString txt) { txt.remove(dirRegExp); txt = txt.trimmed(); if (txt.isRightToLeft()) { return QLatin1String("rtl"); } else { return QLatin1String("ltr"); } } QString PostWidget::formatDateTime(const QDateTime &time) { if (!time.isValid()) { return tr("Invalid Time"); } auto seconds = time.secsTo(QDateTime::currentDateTime()); if (seconds <= 15) { d->mTimer.setInterval(_15SECS); return i18n("Just now"); } if (seconds <= 45) { d->mTimer.setInterval(_15SECS); return i18np("1 sec ago", "%1 secs ago", seconds); } auto minutes = (seconds - 45 + 59) / 60; if (minutes <= 45) { d->mTimer.setInterval(_MINUTE); return i18np("1 min ago", "%1 mins ago", minutes); } auto hours = (seconds - 45 * 60 + 3599) / 3600; if (hours <= 18) { d->mTimer.setInterval(_MINUTE * 15); return i18np("1 hour ago", "%1 hours ago", hours); } d->mTimer.setInterval(_HOUR); auto days = (seconds - 18 * 3600 + 24 * 3600 - 1) / (24 * 3600); return i18np("1 day ago", "%1 days ago", days); } void PostWidget::removeCurrentPost() { if (KMessageBox::warningYesNo(this, i18n("Are you sure you want to remove this post from the server?")) == KMessageBox::Yes) { - connect(d->mCurrentAccount->microblog(), SIGNAL(postRemoved(Choqok::Account*,Choqok::Post*)), - SLOT(slotCurrentPostRemoved(Choqok::Account*,Choqok::Post*))); - connect(d->mCurrentAccount->microblog(), - SIGNAL(errorPost(Choqok::Account*,Choqok::Post*,Choqok::MicroBlog::ErrorType,QString)), - this, SLOT(slotPostError(Choqok::Account*,Choqok::Post*,Choqok::MicroBlog::ErrorType,QString))); + connect(d->mCurrentAccount->microblog(), &MicroBlog::postRemoved, + this, &PostWidget::slotCurrentPostRemoved); + connect(d->mCurrentAccount->microblog(), &MicroBlog::errorPost, this, &PostWidget::slotPostError); setReadWithSignal(); d->mCurrentAccount->microblog()->removePost(d->mCurrentAccount, d->mCurrentPost); } } void PostWidget::slotCurrentPostRemoved(Account *theAccount, Post *post) { if (theAccount == currentAccount() && post == d->mCurrentPost) { this->close(); } } void PostWidget::slotResendPost() { QString text = generateResendText(); setReadWithSignal(); if ((BehaviorSettings::resendWithQuickPost() || currentAccount()->isReadOnly()) && Global::quickPostWidget()) { Global::quickPostWidget()->setText(text); } else { Q_EMIT resendPost(text); } } QString PostWidget::generateResendText() { if (BehaviorSettings::useCustomRT()) { return QString(BehaviorSettings::customRT()) + QLatin1String(" @") + currentPost()->author.userName + QLatin1String(": ") + currentPost()->content; } else { QChar re(0x267B); return QString(re) + QLatin1String(" @") + currentPost()->author.userName + QLatin1String(": ") + currentPost()->content; } } void PostWidget::fetchImage() { if (d->imageUrl.isEmpty()) { return; } QPixmap pix = MediaManager::self()->fetchImage(d->imageUrl, MediaManager::Async); if (!pix.isNull()) { slotImageFetched(d->imageUrl, pix); } else { - connect(MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(slotImageFetched(QUrl,QPixmap))); + connect(MediaManager::self(), &MediaManager::imageFetched, this, + &PostWidget::slotImageFetched); } } void PostWidget::slotImageFetched(const QUrl &remoteUrl, const QPixmap &pixmap) { if (remoteUrl == d->imageUrl) { - disconnect(MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), this, SLOT(slotImageFetched(QUrl,QPixmap))); + disconnect(MediaManager::self(), &MediaManager::imageFetched, this, &PostWidget::slotImageFetched); d->originalImage = pixmap; updatePostImage( width() ); updateUi(); } } void PostWidget::setupAvatar() { QPixmap pix = MediaManager::self()->fetchImage(d->mCurrentPost->author.profileImageUrl, MediaManager::Async); if (!pix.isNull()) { avatarFetched(d->mCurrentPost->author.profileImageUrl, pix); } else { - connect(MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(avatarFetched(QUrl,QPixmap))); - connect(MediaManager::self(), SIGNAL(fetchError(QString,QString)), - this, SLOT(avatarFetchError(QString,QString))); + connect(MediaManager::self(), &MediaManager::imageFetched, this, &PostWidget::avatarFetched); + connect(MediaManager::self(), &MediaManager::fetchError, this, &PostWidget::avatarFetchError); } } void PostWidget::avatarFetched(const QUrl &remoteUrl, const QPixmap &pixmap) { if (remoteUrl == d->mCurrentPost->author.profileImageUrl) { const QUrl url(QLatin1String("img://profileImage")); _mainWidget->document()->addResource(QTextDocument::ImageResource, url, pixmap); updateUi(); - disconnect(MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(avatarFetched(QUrl,QPixmap))); - disconnect(MediaManager::self(), SIGNAL(fetchError(QString,QString)), - this, SLOT(avatarFetchError(QString,QString))); + disconnect(MediaManager::self(), &MediaManager::imageFetched, this, &PostWidget::avatarFetched); + disconnect(MediaManager::self(), &MediaManager::fetchError, this, &PostWidget::avatarFetchError); } } void PostWidget::avatarFetchError(const QUrl &remoteUrl, const QString &errMsg) { Q_UNUSED(errMsg); if (remoteUrl == d->mCurrentPost->author.profileImageUrl) { ///Avatar fetching is failed! but will not disconnect to get the img if it fetches later! const QUrl url(QLatin1String("img://profileImage")); _mainWidget->document()->addResource(QTextDocument::ImageResource, url, QIcon::fromTheme(QLatin1String("image-missing")).pixmap(48)); updateUi(); } } QMap &PostWidget::buttons() { return d->mUiButtons; } void PostWidget::slotPostError(Account *theAccount, Choqok::Post *post, MicroBlog::ErrorType , const QString &errorMessage) { if (theAccount == currentAccount() && post == d->mCurrentPost) { qCDebug(CHOQOK) << errorMessage; - disconnect(d->mCurrentAccount->microblog(), SIGNAL(postRemoved(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotCurrentPostRemoved(Choqok::Account*,Choqok::Post*))); - disconnect(d->mCurrentAccount->microblog(), - SIGNAL(errorPost(Account*,Post*,Choqok::MicroBlog::ErrorType,QString)), - this, SLOT(slotPostError(Account*,Post*,Choqok::MicroBlog::ErrorType,QString))); + disconnect(d->mCurrentAccount->microblog(), &MicroBlog::postRemoved, + this, &PostWidget::slotCurrentPostRemoved); + disconnect(d->mCurrentAccount->microblog(), &MicroBlog::errorPost, + this, &PostWidget::slotPostError); } } QString PostWidget::avatarText() const { return d->mProfileImage; } void PostWidget::setAvatarText(const QString &text) { d->mProfileImage = text; updateUi(); } QString PostWidget::content() const { return d->mContent; } void PostWidget::setContent(const QString &content) { d->mContent = content; updateUi(); } QStringList PostWidget::urls() { return d->detectedUrls; } QString PostWidget::sign() const { return d->mSign; } void PostWidget::setSign(const QString &sign) { d->mSign = sign; updateUi(); } void PostWidget::deleteLater() { close(); } TextBrowser *PostWidget::mainWidget() { return _mainWidget; } void PostWidget::wheelEvent(QWheelEvent *event) { event->ignore(); } void PostWidget::addAction(QAction *action) { TextBrowser::addAction(action); } TimelineWidget *PostWidget::timelineWidget() const { return d->timeline; } class PostWidgetUserData::Private { public: Private(PostWidget *postwidget) : postWidget(postwidget) {} PostWidget *postWidget; }; PostWidgetUserData::PostWidgetUserData(PostWidget *postWidget) : QObjectUserData(), d(new Private(postWidget)) { } PostWidgetUserData::~PostWidgetUserData() { delete d; } PostWidget *PostWidgetUserData::postWidget() { return d->postWidget; } void PostWidgetUserData::setPostWidget(PostWidget *widget) { d->postWidget = widget; } QString PostWidget::getBaseStyle() { return baseStyle; } bool PostWidget::isRemoveAvailable() { return d->mCurrentAccount->username().compare(d->mCurrentPost->author.userName, Qt::CaseInsensitive) == 0; } bool PostWidget::isResendAvailable() { return d->mCurrentAccount->username().compare(d->mCurrentPost->author.userName, Qt::CaseInsensitive) != 0; } void PostWidget::setExtraContents(const QString& text) { d->extraContents = text; } QString PostWidget::extraContents() const { return d->extraContents; } diff --git a/libchoqok/ui/quickpost.cpp b/libchoqok/ui/quickpost.cpp index d65085a2..67a0df45 100644 --- a/libchoqok/ui/quickpost.cpp +++ b/libchoqok/ui/quickpost.cpp @@ -1,291 +1,281 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "quickpost.h" #include #include #include #include #include #include #include #include "accountmanager.h" #include "choqokbehaviorsettings.h" #include "choqoktextedit.h" #include "libchoqokdebug.h" #include "microblog.h" #include "notifymanager.h" #include "shortenmanager.h" #include "uploadmediadialog.h" using namespace Choqok::UI; using namespace Choqok; class QuickPost::Private { public: Private() : submittedPost(0), isPostSubmitted(false) {} QCheckBox *all; QComboBox *comboAccounts; TextEdit *txtPost; QHash< QString, Account * > accountsList; Post *submittedPost; QList submittedAccounts; bool isPostSubmitted; QPushButton *attach; // QString replyToId; }; QuickPost::QuickPost(QWidget *parent) : QDialog(parent), d(new Private) { qCDebug(CHOQOK); setupUi(); loadAccounts(); - connect(d->comboAccounts, SIGNAL(currentIndexChanged(int)), - this, SLOT(slotCurrentAccountChanged(int))); - connect(d->txtPost, SIGNAL(returnPressed(QString)), - this, SLOT(submitPost(QString))); - connect(d->all, SIGNAL(toggled(bool)), - this, SLOT(checkAll(bool))); - connect(AccountManager::self(), SIGNAL(accountAdded(Choqok::Account*)), - this, SLOT(addAccount(Choqok::Account*))); - connect(AccountManager::self(), SIGNAL(accountRemoved(QString)), - this, SLOT(removeAccount(QString))); - connect(d->attach, SIGNAL(clicked(bool)), - this, SLOT(slotAttachMedium())); + connect(d->comboAccounts, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &QuickPost::slotCurrentAccountChanged); + connect(d->txtPost, &TextEdit::returnPressed, this, &QuickPost::submitPost); + connect(d->all, &QCheckBox::toggled, this, &QuickPost::checkAll); + connect(AccountManager::self(), &AccountManager::accountAdded, this, &QuickPost::addAccount); + connect(AccountManager::self(), &AccountManager::accountRemoved, this, &QuickPost::removeAccount); + connect(d->attach, &QPushButton::clicked, this, &QuickPost::slotAttachMedium); d->all->setChecked(Choqok::BehaviorSettings::all()); slotCurrentAccountChanged(d->comboAccounts->currentIndex()); } void QuickPost::setupUi() { resize(Choqok::BehaviorSettings::quickPostDialogSize()); d->all = new QCheckBox(i18nc("All accounts", "All"), this); d->comboAccounts = new QComboBox(this); d->attach = new QPushButton(QIcon::fromTheme(QLatin1String("mail-attachment")), QString(), this); d->attach->setMaximumWidth(d->attach->height()); d->attach->setToolTip(i18n("Attach a file")); QVBoxLayout *mainLayout = new QVBoxLayout(this); QHBoxLayout *hLayout = new QHBoxLayout; hLayout->addWidget(d->all); hLayout->addWidget(d->comboAccounts); hLayout->addWidget(d->attach); mainLayout->addLayout(hLayout); d->txtPost = new TextEdit(0, this); d->txtPost->setTabChangesFocus(true); mainLayout->addWidget(d->txtPost); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); okButton->setText(i18nc("Submit post", "Submit")); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QuickPost::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QuickPost::reject); mainLayout->addWidget(buttonBox); setLayout(mainLayout); d->txtPost->setFocus(Qt::OtherFocusReason); setWindowTitle(i18n("Quick Post")); } QuickPost::~QuickPost() { BehaviorSettings::setAll(d->all->isChecked()); BehaviorSettings::setQuickPostDialogSize(this->size()); BehaviorSettings::self()->save(); delete d; qCDebug(CHOQOK); } void QuickPost::show() { d->txtPost->setFocus(Qt::OtherFocusReason); QDialog::show(); } void QuickPost::slotSubmitPost(Account *a, Post *post) { if (post == d->submittedPost && d->submittedAccounts.removeOne(a)) { Q_EMIT newPostSubmitted(Success, d->submittedPost); } if (d->isPostSubmitted && d->submittedAccounts.isEmpty()) { d->txtPost->setEnabled(true); d->txtPost->clear(); delete d->submittedPost; d->submittedPost = nullptr; d->isPostSubmitted = false; } } void QuickPost::postError(Account *a, Choqok::Post *post, Choqok::MicroBlog::ErrorType , const QString &) { if (post == d->submittedPost && d->submittedAccounts.contains(a)) { d->txtPost->setEnabled(true); Q_EMIT newPostSubmitted(Fail, post); //Choqok crashes without post :( show(); } if (d->submittedAccounts.isEmpty()) { d->txtPost->setEnabled(true); delete d->submittedPost; d->submittedPost = nullptr; } } void QuickPost::submitPost(const QString &txt) { qCDebug(CHOQOK); if (txt.isEmpty()) { KMessageBox::error(choqokMainWindow, i18n("Cannot create a post without any text.")); return; } Choqok::Account *currentAccount = d->accountsList.value(d->comboAccounts->currentText()); if (!currentAccount) { KMessageBox::error(choqokMainWindow, i18n("Please configure at least one account to be included in \"Quick Post\".\nSettings -> Configure Choqok... -> Accounts")); return; } this->hide(); d->submittedAccounts.clear(); QString newPost = txt; if (currentAccount->postCharLimit() && txt.size() > (int)currentAccount->postCharLimit()) { newPost = Choqok::ShortenManager::self()->parseText(txt); } delete d->submittedPost; if (d->all->isChecked()) { d->submittedPost = new Post; d->submittedPost->content = newPost; d->submittedPost->isPrivate = false; for (Account *acc: d->accountsList) { acc->microblog()->createPost(acc, d->submittedPost); d->submittedAccounts << acc; } } else { d->submittedPost = new Post; d->submittedPost->content = newPost; d->submittedPost->isPrivate = false; d->submittedAccounts << currentAccount; currentAccount->microblog()->createPost(d->accountsList.value(d->comboAccounts->currentText()), d->submittedPost); } d->isPostSubmitted = true; } void QuickPost::accept() { qCDebug(CHOQOK); submitPost(d->txtPost->toPlainText()); } void QuickPost::loadAccounts() { qCDebug(CHOQOK); for (Choqok::Account *ac: AccountManager::self()->accounts()) { addAccount(ac); } } void QuickPost::addAccount(Choqok::Account *account) { qCDebug(CHOQOK); - connect(account, SIGNAL(modified(Choqok::Account*)), SLOT(accountModified(Choqok::Account*))); //Added for later changes + connect(account, &Account::modified, this, &QuickPost::accountModified); //Added for later changes if (!account->isEnabled() || account->isReadOnly() || !account->showInQuickPost()) { return; } d->accountsList.insert(account->alias(), account); d->comboAccounts->addItem(QIcon::fromTheme(account->microblog()->pluginIcon()), account->alias()); - connect(account->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - SLOT(slotSubmitPost(Choqok::Account*,Choqok::Post*))); - connect(account->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, - Choqok::MicroBlog::ErrorType, QString)), - SLOT(postError(Choqok::Account *, Choqok::Post *, - Choqok::MicroBlog::ErrorType, QString))); + connect(account->microblog(), &MicroBlog::postCreated, this, &QuickPost::slotSubmitPost); + connect(account->microblog(), &MicroBlog::errorPost, this, &QuickPost::postError); } void QuickPost::removeAccount(const QString &alias) { qCDebug(CHOQOK); d->accountsList.remove(alias); d->comboAccounts->removeItem(d->comboAccounts->findText(alias)); } void QuickPost::checkAll(bool isAll) { d->comboAccounts->setEnabled(!isAll); } void QuickPost::setText(const QString &text) { d->txtPost->setPlainText(text); this->show(); // if(account) // d->comboAccounts->setCurrentItem(account->alias()); // if(!replyToId.isEmpty()) // d->replyToId = replyToId; } void QuickPost::appendText(const QString &text) { d->txtPost->appendText(text); this->show(); } void QuickPost::slotCurrentAccountChanged(int index) { Q_UNUSED(index) if (!d->accountsList.isEmpty()) { d->txtPost->setCharLimit(d->accountsList.value(d->comboAccounts->currentText())->postCharLimit()); } } void QuickPost::accountModified(Account *theAccount) { qCDebug(CHOQOK); if (theAccount->isEnabled() && !theAccount->isReadOnly() && theAccount->showInQuickPost()) { if (!d->accountsList.contains(theAccount->alias())) { addAccount(theAccount); } } else if (d->accountsList.contains(theAccount->alias())) { removeAccount(theAccount->alias()); } } void QuickPost::slotAttachMedium() { KMessageBox::information(this, i18n("Link to uploaded medium will be added here after uploading process succeed."), QString(), QLatin1String("quickPostAttachMedium")); QPointer dlg = new UploadMediaDialog(this); dlg->show(); } diff --git a/libchoqok/ui/textbrowser.cpp b/libchoqok/ui/textbrowser.cpp index 78888883..9ef81432 100644 --- a/libchoqok/ui/textbrowser.cpp +++ b/libchoqok/ui/textbrowser.cpp @@ -1,178 +1,178 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "textbrowser.h" #include #include #include #include #include #include #include #include #include #include #include "postwidget.h" using namespace Choqok::UI; class TextBrowser::Private { public: Private() : isPressedForDrag(false) {} static QList< QPointer > actions; PostWidget *parent; QPoint dragStartPosition; bool isPressedForDrag; }; QList< QPointer > TextBrowser::Private::actions; TextBrowser::TextBrowser(QWidget *parent) : QTextBrowser(parent), d(new Private) { d->parent = qobject_cast(parent); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setOpenLinks(false); } TextBrowser::~TextBrowser() { delete d; } void TextBrowser::mousePressEvent(QMouseEvent *ev) { Q_EMIT clicked(ev); if (ev->button() == Qt::LeftButton) { if (!cursorForPosition(ev->pos()).hasSelection() && !anchorAt(ev->pos()).isEmpty()) { d->dragStartPosition = ev->pos(); d->isPressedForDrag = true; } else { d->isPressedForDrag = false; } } ev->accept(); QTextBrowser::mousePressEvent(ev); } void TextBrowser::mouseMoveEvent(QMouseEvent *ev) { if ((ev->buttons() & Qt::LeftButton) && d->isPressedForDrag) { QPoint diff = ev->pos() - d->dragStartPosition; if (diff.manhattanLength() > QApplication::startDragDistance()) { QString anchor = anchorAt(d->dragStartPosition); if (!anchor.isEmpty()) { QDrag *drag = new QDrag(this); QMimeData *mimeData; mimeData = new QMimeData; QList urls; urls.append(QUrl(anchor)); mimeData->setUrls(urls); mimeData->setText(anchor); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction | Qt::MoveAction); } } else { QTextBrowser::mouseMoveEvent(ev); } } else { QTextBrowser::mouseMoveEvent(ev); } ev->accept(); } void TextBrowser::resizeEvent(QResizeEvent *e) { QTextEdit::resizeEvent(e); } void TextBrowser::contextMenuEvent(QContextMenuEvent *event) { QMenu *menu = new QMenu(this); QAction *copy = new QAction(i18nc("Copy text", "Copy"), this); // copy->setShortcut( KShortcut( Qt::ControlModifier | Qt::Key_C ) ); - connect(copy, SIGNAL(triggered(bool)), SLOT(slotCopyPostContent())); + connect(copy, &QAction::triggered, this, &TextBrowser::slotCopyPostContent); menu->addAction(copy); QString anchor = document()->documentLayout()->anchorAt(event->pos()); if (!anchor.isEmpty()) { QAction *copyLink = new QAction(i18n("Copy Link Location"), this); copyLink->setData(anchor); - connect(copyLink, SIGNAL(triggered(bool)), SLOT(slotCopyLink())); + connect(copyLink, &QAction::triggered, this, &TextBrowser::slotCopyLink); menu->addAction(copyLink); } QAction *selectAll = new QAction(i18nc("Select all text", "Select All"), this); // selectAll->setShortcut( KShortcut( Qt::ControlModifier | Qt::Key_A ) ); - connect(selectAll, SIGNAL(triggered(bool)), SLOT(selectAll())); + connect(selectAll, &QAction::triggered, this, &TextBrowser::selectAll); menu->addAction(selectAll); menu->addSeparator(); for (QAction *act: d->actions) { if (act) { act->setUserData(32, new PostWidgetUserData(d->parent)); menu->addAction(act); } } menu->popup(event->globalPos()); } void TextBrowser::slotCopyPostContent() { QString txt = textCursor().selectedText(); if (txt.isEmpty()) { PostWidget *paPost = qobject_cast(parentWidget()); if (paPost) { QApplication::clipboard()->setText(paPost->currentPost()->content); } } else { QApplication::clipboard()->setText(txt); } } void TextBrowser::slotCopyLink() { QAction *act = qobject_cast< QAction * >(sender()); if (act) { QString link = act->data().toString(); QApplication::clipboard()->setText(link); } } void Choqok::UI::TextBrowser::wheelEvent(QWheelEvent *event) { event->ignore(); } void Choqok::UI::TextBrowser::addAction(QAction *action) { if (action) { Private::actions.append(action); } } diff --git a/libchoqok/ui/timelinewidget.cpp b/libchoqok/ui/timelinewidget.cpp index 0cf5c01d..5d4206e4 100644 --- a/libchoqok/ui/timelinewidget.cpp +++ b/libchoqok/ui/timelinewidget.cpp @@ -1,388 +1,384 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "timelinewidget.h" #include #include #include #include #include #include #include #include #include "account.h" #include "choqokappearancesettings.h" #include "choqokbehaviorsettings.h" #include "libchoqokdebug.h" #include "microblog.h" #include "postwidget.h" #include "notifymanager.h" namespace Choqok { namespace UI { class TimelineWidget::Private { public: Private(Account *account, const QString &timelineName) : currentAccount(account), timelineName(timelineName), btnMarkAllAsRead(0), unreadCount(0), placeholderLabel(0), info(0), isClosable(false) { if (account->microblog()->isValidTimeline(timelineName)) { info = account->microblog()->timelineInfo(timelineName); } else {//It's search timeline info = new Choqok::TimelineInfo; info->name = timelineName; info->description = i18nc("%1 is the name of a timeline", "Search results for %1", timelineName); } } Account *currentAccount; QString timelineName; bool mStartUp; QPointer btnMarkAllAsRead; int unreadCount; QMap posts; QMultiMap sortedPostsList; QVBoxLayout *mainLayout; QHBoxLayout *titleBarLayout; QLabel *lblDesc; QLabel *placeholderLabel; QScrollArea *scrollArea; int order; // 0: web, -1: natural Choqok::TimelineInfo *info; bool isClosable; QIcon timelineIcon; }; TimelineWidget::TimelineWidget(Choqok::Account *account, const QString &timelineName, QWidget *parent /*= 0*/) : QWidget(parent), d(new Private(account, timelineName)) { setAttribute(Qt::WA_DeleteOnClose); setupUi(); loadTimeline(); } TimelineWidget::~TimelineWidget() { delete d; } void TimelineWidget::loadTimeline() { QList list = currentAccount()->microblog()->loadTimeline(currentAccount(), timelineName()); - connect(currentAccount()->microblog(), SIGNAL(saveTimelines()), SLOT(saveTimeline())); + connect(currentAccount()->microblog(), &MicroBlog::saveTimelines, this, &TimelineWidget::saveTimeline); if (!BehaviorSettings::markAllAsReadOnExit()) { addNewPosts(list); } else { for (Choqok::Post *p: list) { PostWidget *pw = d->currentAccount->microblog()->createPostWidget(d->currentAccount, p, this); if (pw) { pw->setRead(); addPostWidgetToUi(pw); } } } } QString TimelineWidget::timelineName() { return d->timelineName; } QString TimelineWidget::timelineInfoName() { return d->info->name; } QString TimelineWidget::timelineIconName() { return d->info->icon; } void TimelineWidget::setTimelineIcon(const QIcon &icon) { d->timelineIcon = icon; } QIcon &TimelineWidget::timelineIcon() const { return d->timelineIcon; } void TimelineWidget::setTimelineName(const QString &type) { d->timelineName = type; } void TimelineWidget::setupUi() { d->lblDesc = new QLabel(this); TimelineInfo *info = currentAccount()->microblog()->timelineInfo(d->timelineName); if (info) { d->lblDesc->setText(info->description.toHtmlEscaped()); } d->lblDesc->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); d->lblDesc->setWordWrap(true); d->lblDesc->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); QFont fnt = d->lblDesc->font(); fnt.setBold(true); d->lblDesc->setFont(fnt); QVBoxLayout *gridLayout; QWidget *scrollAreaWidgetContents; QVBoxLayout *verticalLayout_2; QSpacerItem *verticalSpacer; gridLayout = new QVBoxLayout(this); gridLayout->setMargin(0); gridLayout->setObjectName(QLatin1String("gridLayout")); d->scrollArea = new QScrollArea(this); d->scrollArea->setObjectName(QLatin1String("scrollArea")); d->scrollArea->setFrameShape(QFrame::NoFrame); d->scrollArea->setWidgetResizable(true); scrollAreaWidgetContents = new QWidget(); scrollAreaWidgetContents->setObjectName(QLatin1String("scrollAreaWidgetContents")); scrollAreaWidgetContents->setGeometry(QRect(0, 0, 254, 300)); verticalLayout_2 = new QVBoxLayout(scrollAreaWidgetContents); verticalLayout_2->setMargin(1); d->mainLayout = new QVBoxLayout(); verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); d->mainLayout->addItem(verticalSpacer); d->mainLayout->setSpacing(5); d->mainLayout->setMargin(1); d->titleBarLayout = new QHBoxLayout; d->titleBarLayout->addWidget(d->lblDesc); verticalLayout_2->addLayout(d->mainLayout); d->scrollArea->setWidget(scrollAreaWidgetContents); gridLayout->addLayout(d->titleBarLayout); gridLayout->addWidget(d->scrollArea); if (AppearanceSettings::useReverseOrder()) { d->order = -1; QTimer::singleShot(0, this, SLOT(scrollToBottom())); } else { d->order = 0; } } void TimelineWidget::removeOldPosts() { int count = d->sortedPostsList.count() - BehaviorSettings::countOfPosts(); // qCDebug(CHOQOK)< 0 && !d->sortedPostsList.isEmpty()) { PostWidget *wd = d->sortedPostsList.values().first(); if (wd && wd->isRead()) { wd->close(); } --count; } } void TimelineWidget::addPlaceholderMessage(const QString &msg) { if ( d->posts.isEmpty() ) { if (!d->placeholderLabel) { d->placeholderLabel = new QLabel(this); d->mainLayout->insertWidget(d->order, d->placeholderLabel); } d->placeholderLabel->setText(msg); } } void TimelineWidget::addNewPosts(QList< Choqok::Post * > &postList) { qCDebug(CHOQOK) << d->currentAccount->alias() << d->timelineName << postList.count(); int unread = 0; for (Choqok::Post *p: postList) { if (d->posts.keys().contains(p->postId)) { continue; } PostWidget *pw = d->currentAccount->microblog()->createPostWidget(d->currentAccount, p, this); if (pw) { addPostWidgetToUi(pw); if (!pw->isRead()) { ++unread; } } } removeOldPosts(); if (unread) { d->unreadCount += unread; Choqok::NotifyManager::newPostArrived(i18np("1 new post in %2(%3)", "%1 new posts in %2(%3)", unread, currentAccount()->alias(), d->timelineName)); Q_EMIT updateUnreadCount(unread); showMarkAllAsReadButton(); } } void TimelineWidget::showMarkAllAsReadButton() { if (d->btnMarkAllAsRead) { delete d->btnMarkAllAsRead; } d->btnMarkAllAsRead = new QPushButton(this); d->btnMarkAllAsRead->setIcon(QIcon::fromTheme(QLatin1String("mail-mark-read"))); d->btnMarkAllAsRead->setToolTip(i18n("Mark timeline as read")); d->btnMarkAllAsRead->setMaximumSize(14, 14); d->btnMarkAllAsRead->setIconSize(QSize(12, 12)); - connect(d->btnMarkAllAsRead, SIGNAL(clicked(bool)), SLOT(markAllAsRead())); + connect(d->btnMarkAllAsRead, &QPushButton::clicked, this, &TimelineWidget::markAllAsRead); d->titleBarLayout->addWidget(d->btnMarkAllAsRead); } void TimelineWidget::addPostWidgetToUi(PostWidget *widget) { widget->initUi(); widget->setFocusProxy(this); widget->setObjectName(widget->currentPost()->postId); - connect(widget, SIGNAL(resendPost(QString)), - this, SIGNAL(forwardResendPost(QString))); - connect(widget, SIGNAL(reply(QString,QString,QString)), - this, SIGNAL(forwardReply(QString,QString,QString))); - connect(widget, SIGNAL(postReaded()), - this, SLOT(slotOnePostReaded())); - connect(widget, SIGNAL(aboutClosing(QString,PostWidget*)), - SLOT(postWidgetClosed(QString,PostWidget*))); + connect(widget, &PostWidget::resendPost, this, &TimelineWidget::forwardResendPost); + connect(widget, &PostWidget::reply, this, &TimelineWidget::forwardReply); + connect(widget, &PostWidget::postReaded, this, &TimelineWidget::slotOnePostReaded); + connect(widget, &PostWidget::aboutClosing, this, &TimelineWidget::postWidgetClosed); d->mainLayout->insertWidget(d->order, widget); d->posts.insert(widget->currentPost()->postId, widget); d->sortedPostsList.insert(widget->currentPost()->creationDateTime, widget); Global::SessionManager::self()->emitNewPostWidgetAdded(widget, currentAccount(), timelineName()); if (d->placeholderLabel) { d->mainLayout->removeWidget(d->placeholderLabel); delete d->placeholderLabel; d->placeholderLabel = 0; } } int TimelineWidget::unreadCount() const { return d->unreadCount; } void TimelineWidget::setUnreadCount(int unread) { d->unreadCount = unread; } void TimelineWidget::markAllAsRead() { if (d->unreadCount > 0) { for (PostWidget *pw: d->sortedPostsList) { pw->setRead(); } int unread = -d->unreadCount; d->unreadCount = 0; Q_EMIT updateUnreadCount(unread); d->btnMarkAllAsRead->deleteLater(); } } void TimelineWidget::scrollToBottom() { d->scrollArea->verticalScrollBar()-> triggerAction(QAbstractSlider::SliderToMaximum); } Account *TimelineWidget::currentAccount() { return d->currentAccount; } void TimelineWidget::settingsChanged() { for (PostWidget *pw: d->sortedPostsList) { pw->setUiStyle(); } } void TimelineWidget::slotOnePostReaded() { d->unreadCount--; Q_EMIT updateUnreadCount(-1); if (d->unreadCount == 0) { d->btnMarkAllAsRead->deleteLater(); } } void TimelineWidget::saveTimeline() { if (currentAccount()->microblog()) { currentAccount()->microblog()->saveTimeline(currentAccount(), timelineName(), posts().values()); } } QList< PostWidget * > TimelineWidget::postWidgets() { return posts().values(); } void TimelineWidget::postWidgetClosed(const QString &postId, PostWidget *post) { d->posts.remove(postId); d->sortedPostsList.remove(post->currentPost()->creationDateTime, post); } QMap< QString, PostWidget * > &TimelineWidget::posts() const { return d->posts; } QMultiMap< QDateTime, PostWidget * > &TimelineWidget::sortedPostsList() const { return d->sortedPostsList; } QLabel *TimelineWidget::timelineDescription() { return d->lblDesc; } QVBoxLayout *TimelineWidget::mainLayout() { return d->mainLayout; } QHBoxLayout *TimelineWidget::titleBarLayout() { return d->titleBarLayout; } bool TimelineWidget::isClosable() const { return d->isClosable; } void TimelineWidget::setClosable(bool isClosable) { d->isClosable = isClosable; } } } diff --git a/libchoqok/ui/uploadmediadialog.cpp b/libchoqok/ui/uploadmediadialog.cpp index 30c17c23..f7b962ad 100644 --- a/libchoqok/ui/uploadmediadialog.cpp +++ b/libchoqok/ui/uploadmediadialog.cpp @@ -1,277 +1,279 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "uploadmediadialog.h" #include "ui_uploadmedia_base.h" +#include #include #include #include #include #include #include #include #include #include #include #include "choqokbehaviorsettings.h" #include "choqokuiglobal.h" #include "libchoqokdebug.h" #include "pluginmanager.h" #include "mediamanager.h" #include "quickpost.h" #include "uploader.h" using namespace Choqok::UI; class UploadMediaDialog::Private { public: Ui::UploadMediaBase ui; QMap availablePlugins; QList moduleProxyList; QUrl localUrl; QPointer progress; }; UploadMediaDialog::UploadMediaDialog(QWidget *parent, const QString &url) : QDialog(parent), d(new Private) { setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(i18n("Upload Medium")); d->ui.setupUi(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); okButton->setText(i18n("Upload")); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &UploadMediaDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &UploadMediaDialog::reject); d->ui.verticalLayout->addWidget(buttonBox); adjustSize(); - connect(d->ui.imageUrl, SIGNAL(textChanged(QString)), - this, SLOT(slotMediumChanged(QString))); + connect(d->ui.imageUrl, &KUrlRequester::textChanged, + this, &UploadMediaDialog::slotMediumChanged); load(); if (url.isEmpty()) { d->ui.imageUrl->button()->click(); } else { d->ui.imageUrl->setUrl(QUrl(url)); } - connect(d->ui.uploaderPlugin, SIGNAL(currentIndexChanged(int)), SLOT(currentPluginChanged(int))); + connect(d->ui.uploaderPlugin, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &UploadMediaDialog::currentPluginChanged); d->ui.aboutPlugin->setIcon(QIcon::fromTheme(QLatin1String("help-about"))); d->ui.configPlugin->setIcon(QIcon::fromTheme(QLatin1String("configure"))); - connect(d->ui.aboutPlugin, SIGNAL(clicked(bool)), SLOT(slotAboutClicked())); - connect(d->ui.configPlugin, SIGNAL(clicked(bool)), SLOT(slotConfigureClicked())); - connect(Choqok::MediaManager::self(), SIGNAL(mediumUploaded(QUrl,QString)), - SLOT(slotMediumUploaded(QUrl,QString))); - connect(Choqok::MediaManager::self(), SIGNAL(mediumUploadFailed(QUrl,QString)), - SLOT(slotMediumUploadFailed(QUrl,QString))); + connect(d->ui.aboutPlugin, &QPushButton::clicked, this, &UploadMediaDialog::slotAboutClicked); + connect(d->ui.configPlugin, &QPushButton::clicked, this, &UploadMediaDialog::slotConfigureClicked); + connect(Choqok::MediaManager::self(), &MediaManager::mediumUploaded, + this, &UploadMediaDialog::slotMediumUploaded); + connect(Choqok::MediaManager::self(), &MediaManager::mediumUploadFailed, + this, &UploadMediaDialog::slotMediumUploadFailed); } UploadMediaDialog::~UploadMediaDialog() { delete d; } void UploadMediaDialog::load() { QList plugins = Choqok::PluginManager::self()->availablePlugins(QLatin1String("Uploaders")); qCDebug(CHOQOK) << plugins.count(); for (const KPluginInfo &plugin: plugins) { d->ui.uploaderPlugin->addItem(QIcon::fromTheme(plugin.icon()), plugin.name(), plugin.pluginName()); d->availablePlugins.insert(plugin.pluginName(), plugin); } d->ui.uploaderPlugin->setCurrentIndex(d->ui.uploaderPlugin->findData(Choqok::BehaviorSettings::lastUsedUploaderPlugin())); if (d->ui.uploaderPlugin->currentIndex() == -1 && d->ui.uploaderPlugin->count() > 0) { d->ui.uploaderPlugin->setCurrentIndex(0); } } void UploadMediaDialog::accept() { if (d->ui.uploaderPlugin->currentIndex() == -1 || !QFile::exists(d->ui.imageUrl->url().toLocalFile()) || !QFile(d->ui.imageUrl->url().toLocalFile()).size()) { return; } if (d->progress) { d->progress->deleteLater(); } d->progress = new QProgressBar(this); d->progress->setRange(0, 0); d->progress->setFormat(i18n("Uploading...")); d->ui.verticalLayout->addWidget(d->progress); Choqok::BehaviorSettings::setLastUsedUploaderPlugin(d->ui.uploaderPlugin->itemData(d->ui.uploaderPlugin->currentIndex()).toString()); d->localUrl = d->ui.imageUrl->url(); QString plugin = d->ui.uploaderPlugin->itemData(d->ui.uploaderPlugin->currentIndex()).toString(); showed = true; winSize = size(); Choqok::MediaManager::self()->uploadMedium(d->localUrl, plugin); } void Choqok::UI::UploadMediaDialog::currentPluginChanged(int index) { QString key = d->ui.uploaderPlugin->itemData(index).toString(); // qCDebug(CHOQOK)<ui.configPlugin->setEnabled(!key.isEmpty() && d->availablePlugins.value(key).kcmServices().count() > 0); } void Choqok::UI::UploadMediaDialog::slotAboutClicked() { const QString shorten = d->ui.uploaderPlugin->itemData(d->ui.uploaderPlugin->currentIndex()).toString(); if (shorten.isEmpty()) { return; } KPluginInfo info = d->availablePlugins.value(shorten); KAboutData aboutData(info.name(), info.name(), info.version(), info.comment(), KAboutLicense::byKeyword(info.license()).key(), QString(), QString(), info.website()); aboutData.addAuthor(info.author(), QString(), info.email()); KAboutApplicationDialog aboutPlugin(aboutData, this); aboutPlugin.setWindowIcon(QIcon::fromTheme(info.icon())); aboutPlugin.exec(); } void Choqok::UI::UploadMediaDialog::slotConfigureClicked() { qCDebug(CHOQOK); KPluginInfo pluginInfo = d->availablePlugins.value(d->ui.uploaderPlugin->itemData(d->ui.uploaderPlugin->currentIndex()).toString()); qCDebug(CHOQOK) << pluginInfo.name() << pluginInfo.kcmServices().count(); QPointer configDialog = new QDialog(this); configDialog->setWindowTitle(pluginInfo.name()); // The number of KCModuleProxies in use determines whether to use a tabwidget QTabWidget *newTabWidget = 0; // Widget to use for the setting dialog's main widget, // either a QTabWidget or a KCModuleProxy QWidget *mainWidget = 0; // Widget to use as the KCModuleProxy's parent. // The first proxy is owned by the dialog itself QWidget *moduleProxyParentWidget = configDialog; for (const KService::Ptr &servicePtr: pluginInfo.kcmServices()) { if (!servicePtr->noDisplay()) { KCModuleInfo moduleInfo(servicePtr); KCModuleProxy *currentModuleProxy = new KCModuleProxy(moduleInfo, moduleProxyParentWidget); if (currentModuleProxy->realModule()) { d->moduleProxyList << currentModuleProxy; if (mainWidget && !newTabWidget) { // we already created one KCModuleProxy, so we need a tab widget. // Move the first proxy into the tab widget and ensure this and subsequent // proxies are in the tab widget newTabWidget = new QTabWidget(configDialog); moduleProxyParentWidget = newTabWidget; mainWidget->setParent(newTabWidget); KCModuleProxy *moduleProxy = qobject_cast(mainWidget); if (moduleProxy) { newTabWidget->addTab(mainWidget, moduleProxy->moduleInfo().moduleName()); mainWidget = newTabWidget; } else { delete newTabWidget; newTabWidget = 0; moduleProxyParentWidget = configDialog; mainWidget->setParent(0); } } if (newTabWidget) { newTabWidget->addTab(currentModuleProxy, servicePtr->name()); } else { mainWidget = currentModuleProxy; } } else { delete currentModuleProxy; } } } // it could happen that we had services to show, but none of them were real modules. if (d->moduleProxyList.count()) { QWidget *showWidget = new QWidget(configDialog); QVBoxLayout *layout = new QVBoxLayout; showWidget->setLayout(layout); layout->addWidget(mainWidget); layout->insertSpacing(-1, QApplication::style()->pixelMetric(QStyle::PM_DialogButtonsSeparator)); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), configDialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), configDialog, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, configDialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, configDialog, &QDialog::reject); layout->addWidget(buttonBox); showWidget->adjustSize(); // connect(&configDialog, SIGNAL(defaultClicked()), this, SLOT(slotDefaultClicked())); if (configDialog->exec() == QDialog::Accepted) { for (KCModuleProxy *moduleProxy: d->moduleProxyList) { QStringList parentComponents = moduleProxy->moduleInfo().service()->property(QLatin1String("X-KDE-ParentComponents")).toStringList(); moduleProxy->save(); } } else { for (KCModuleProxy *moduleProxy: d->moduleProxyList) { moduleProxy->load(); } } qDeleteAll(d->moduleProxyList); d->moduleProxyList.clear(); } } void Choqok::UI::UploadMediaDialog::slotMediumUploaded(const QUrl &localUrl, const QString &remoteUrl) { if (d->localUrl == localUrl && showed) { qCDebug(CHOQOK); Global::quickPostWidget()->appendText(remoteUrl); showed = false; close(); } } void Choqok::UI::UploadMediaDialog::slotMediumUploadFailed(const QUrl &localUrl, const QString &errorMessage) { if (d->localUrl == localUrl && showed) { showed = false; KMessageBox::detailedSorry(Global::mainWindow(), i18n("Medium uploading failed."), errorMessage); show(); d->progress->deleteLater(); } resize(winSize); } void Choqok::UI::UploadMediaDialog::slotMediumChanged(const QString &url) { d->ui.previewer->showPreview(QUrl::fromLocalFile(url)); } diff --git a/microblogs/friendica/friendicaeditaccount.cpp b/microblogs/friendica/friendicaeditaccount.cpp index 775fe751..802deeed 100644 --- a/microblogs/friendica/friendicaeditaccount.cpp +++ b/microblogs/friendica/friendicaeditaccount.cpp @@ -1,301 +1,303 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2016 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "friendicaeditaccount.h" #include +#include #include #include #include "accountmanager.h" #include "choqoktools.h" #include "gnusocialapiaccount.h" #include "friendicadebug.h" #include "friendicamicroblog.h" FriendicaEditAccountWidget::FriendicaEditAccountWidget(FriendicaMicroBlog *microblog, GNUSocialApiAccount *account, QWidget *parent) : ChoqokEditAccountWidget(account, parent), mAccount(account), progress(0), isAuthenticated(false) { setupUi(this); // setAuthenticated(false); // connect(kcfg_authorize, SIGNAL(clicked(bool)), SLOT(authorizeUser())); // connect(kcfg_authMethod, SIGNAL(currentIndexChanged(int)), SLOT(slotAuthMethodChanged(int))); // slotAuthMethodChanged(kcfg_authMethod->currentIndex()); - connect(kcfg_host, SIGNAL(editingFinished()), SLOT(slotCheckHostUrl())); + connect(kcfg_host, &QLineEdit::editingFinished, this, + &FriendicaEditAccountWidget::slotCheckHostUrl); if (mAccount) { kcfg_alias->setText(mAccount->alias()); kcfg_host->setText(mAccount->host()); kcfg_api->setText(mAccount->api()); // kcfg_oauthUsername->setText( mAccount->username() ); kcfg_basicUsername->setText(mAccount->username()); kcfg_basicPassword->setText(mAccount->password()); kcfg_changeExclamationMark->setChecked(mAccount->isChangeExclamationMark()); kcfg_changeToString->setText(mAccount->changeExclamationMarkToText()); // if(mAccount->usingOAuth()){ // if( !mAccount->oauthConsumerKey().isEmpty() && // !mAccount->oauthConsumerSecret().isEmpty() && // !mAccount->oauthToken().isEmpty() && // !mAccount->oauthTokenSecret().isEmpty() ) { // setAuthenticated(true); // oauthConsumerKey = mAccount->oauthConsumerKey(); // oauthConsumerSecret = mAccount->oauthConsumerSecret(); // token = mAccount->oauthToken(); // tokenSecret = mAccount->oauthTokenSecret(); // } else { // setAuthenticated(false); // } // kcfg_authMethod->setCurrentIndex(0); // } else { // kcfg_authMethod->setCurrentIndex(1); // } } else { // kcfg_authMethod->setCurrentIndex(0); QString newAccountAlias = microblog->serviceName(); QString servName = newAccountAlias; int counter = 1; while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) { newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter); counter++; } setAccount(mAccount = new GNUSocialApiAccount(microblog, newAccountAlias)); kcfg_alias->setText(newAccountAlias); const QRegExp userRegExp(QLatin1String("([a-z0-9]){1,64}"), Qt::CaseInsensitive); QValidator *userVal = new QRegExpValidator(userRegExp, 0); kcfg_basicUsername->setValidator(userVal); } loadTimelinesTableState(); kcfg_alias->setFocus(Qt::OtherFocusReason); } FriendicaEditAccountWidget::~FriendicaEditAccountWidget() { } bool FriendicaEditAccountWidget::validateData() { // if( kcfg_authMethod->currentIndex()==0 ) {//OAuth // if(kcfg_alias->text().isEmpty() || kcfg_oauthUsername->text().isEmpty() || !isAuthenticated) // return false; // } else {//Basic if (kcfg_alias->text().isEmpty() || kcfg_basicUsername->text().isEmpty() || kcfg_basicPassword->text().isEmpty()) { return false; } // } return true; } Choqok::Account *FriendicaEditAccountWidget::apply() { qCDebug(CHOQOK); /*if(kcfg_authMethod->currentIndex() == 0){ mAccount->setUsername( kcfg_oauthUsername->text() ); mAccount->setOauthToken( token ); mAccount->setOauthConsumerKey( oauthConsumerKey ); mAccount->setOauthConsumerSecret( oauthConsumerSecret ); mAccount->setOauthTokenSecret( tokenSecret ); mAccount->setUsingOAuth(true); } else*/ { mAccount->setUsername(kcfg_basicUsername->text()); mAccount->setPassword(kcfg_basicPassword->text()); mAccount->setUsingOAuth(false); } mAccount->setHost(kcfg_host->text()); mAccount->setApi(kcfg_api->text()); mAccount->setAlias(kcfg_alias->text()); mAccount->setChangeExclamationMark(kcfg_changeExclamationMark->isChecked()); mAccount->setChangeExclamationMarkToText(kcfg_changeToString->text()); saveTimelinesTableState(); setTextLimit(); mAccount->writeConfig(); return mAccount; } // void FriendicaEditAccountWidget::authorizeUser() // { // qCDebug(CHOQOK); // slotCheckHostUrl(); // if(QUrl(kcfg_host->text()).host()!="identi.ca"){ // KMessageBox::sorry(this, i18n("Sorry, OAuth Method just works with Identi.ca server. You have to use basic authentication for other StatusNet servers.")); // kcfg_authMethod->setCurrentIndex(1); // return; // } // qoauth = new QOAuth::Interface(new KIO::Integration::AccessManager(this), this); // //TODO change this to have support for self hosted StatusNets // qoauth->setConsumerKey( oauthConsumerKey ); // qoauth->setConsumerSecret( oauthConsumerSecret ); // qoauth->setRequestTimeout( 10000 ); // // // send a request for an unauthorized token // QString oauthReqTokenUrl = QString("%1/%2/oauth/request_token").arg(kcfg_host->text()).arg(kcfg_api->text()); // // qCDebug(CHOQOK)<requestToken( oauthReqTokenUrl, QOAuth::GET, QOAuth::HMAC_SHA1, params ); // setAuthenticated(false); // kcfg_authorize->setIcon(QIcon::fromTheme("object-locked")); // // // if no error occurred, read the received token and token secret // if ( qoauth->error() == QOAuth::NoError ) { // token = reply.value( QOAuth::tokenParameterName() ); // tokenSecret = reply.value( QOAuth::tokenSecretParameterName() ); // qCDebug(CHOQOK)<<"token: "<text()).arg(kcfg_api->text())); // url.addQueryItem( QOAuth::tokenParameterName(), token ); // url.addQueryItem( "oauth_token", token ); // Choqok::openUrl(url); // kcfg_authorize->setEnabled(false); // getPinCode(); // } else { // qCDebug(CHOQOK)<<"ERROR:" <error()<error()); // KMessageBox::detailedError(this, i18n("Authentication Error"), // Choqok::qoauthErrorText(qoauth->error())); // } // } // // void FriendicaEditAccountWidget::getPinCode() // { // isAuthenticated = false; // while(!isAuthenticated){ // QString verifier = KInputDialog::getText( i18n("Security code"), // i18nc("Security code recieved from StatusNet", // "Enter security code:")); // if(verifier.isEmpty()) // return; // QOAuth::ParamMap otherArgs; // otherArgs.insert( "oauth_verifier", verifier.toUtf8() ); // // QOAuth::ParamMap reply = // qoauth->accessToken( QString("%1/%2/oauth/access_token").arg(kcfg_host->text()).arg(kcfg_api->text()), // QOAuth::GET, token, tokenSecret, QOAuth::HMAC_SHA1, otherArgs ); // // if no error occurred, read the Access Token (and other arguments, if applicable) // if ( qoauth->error() == QOAuth::NoError ) { // sender()->deleteLater(); // kcfg_authorize->setEnabled(true); // token = reply.value( QOAuth::tokenParameterName() ); // tokenSecret = reply.value( QOAuth::tokenSecretParameterName() ); // qCDebug(CHOQOK)<<"token: "<error()<<' '<error()); // KMessageBox::detailedError(this, i18n("Authentication Error"), // Choqok::qoauthErrorText(qoauth->error())); // } // } // } void FriendicaEditAccountWidget::setTextLimit() { QString url = mAccount->host() + QLatin1Char('/') + mAccount->api() + QLatin1String("/statusnet/config.json"); KIO::StoredTransferJob *job = KIO::storedGet(QUrl(url), KIO::Reload, KIO::HideProgressInfo); job->exec(); if (job->error()) { qCCritical(CHOQOK) << "Job error:" << job->errorString(); return; } const QJsonDocument json = QJsonDocument::fromJson(job->data()); if (!json.isNull()) { const QVariantMap siteInfos = json.toVariant().toMap()[QLatin1String("site")].toMap(); bool ok; mAccount->setPostCharLimit(siteInfos[QLatin1String("textlimit")].toUInt(&ok)); if (!ok) { qCDebug(CHOQOK) << "Cannot parse text limit value"; mAccount->setPostCharLimit(140); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } void FriendicaEditAccountWidget::loadTimelinesTableState() { for (const QString &timeline: mAccount->microblog()->timelineNames()) { int newRow = timelinesTable->rowCount(); timelinesTable->insertRow(newRow); Choqok::TimelineInfo *info = mAccount->microblog()->timelineInfo(timeline); QTableWidgetItem *item = new QTableWidgetItem(info->name); item->setData(32, timeline); item->setToolTip(info->description); timelinesTable->setItem(newRow, 0, item); QCheckBox *enable = new QCheckBox(timelinesTable); enable->setChecked(mAccount->timelineNames().contains(timeline)); timelinesTable->setCellWidget(newRow, 1, enable); } } void FriendicaEditAccountWidget::saveTimelinesTableState() { QStringList timelines; int rowCount = timelinesTable->rowCount(); for (int i = 0; i < rowCount; ++i) { QCheckBox *enable = qobject_cast(timelinesTable->cellWidget(i, 1)); if (enable && enable->isChecked()) { timelines << timelinesTable->item(i, 0)->data(32).toString(); } } timelines.removeDuplicates(); mAccount->setTimelineNames(timelines); } // void FriendicaEditAccountWidget::slotAuthMethodChanged(int index) // { // if(index == 0){ // kcfg_BasicBox->hide(); // kcfg_OAuthBox->show(); // } else { // kcfg_BasicBox->show(); // kcfg_OAuthBox->hide(); // } // } // void FriendicaEditAccountWidget::setAuthenticated(bool authenticated) // { // isAuthenticated = authenticated; // if(authenticated){ // kcfg_authorize->setIcon(QIcon::fromTheme("object-unlocked")); // kcfg_authenticateLed->on(); // kcfg_authenticateStatus->setText(i18n("Authenticated")); // } else { // kcfg_authorize->setIcon(QIcon::fromTheme("object-locked")); // kcfg_authenticateLed->off(); // kcfg_authenticateStatus->setText(i18n("Not Authenticated")); // } // } void FriendicaEditAccountWidget::slotCheckHostUrl() { if (!kcfg_host->text().isEmpty() && !kcfg_host->text().startsWith(QLatin1String("http"), Qt::CaseInsensitive) && !kcfg_host->text().startsWith(QLatin1String("https"))) { kcfg_host->setText(kcfg_host->text().prepend(QLatin1String("https://"))); } } diff --git a/microblogs/laconica/laconicaeditaccount.cpp b/microblogs/laconica/laconicaeditaccount.cpp index d3ce22da..5afd5028 100644 --- a/microblogs/laconica/laconicaeditaccount.cpp +++ b/microblogs/laconica/laconicaeditaccount.cpp @@ -1,303 +1,305 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "laconicaeditaccount.h" #include +#include #include #include #include "accountmanager.h" #include "choqoktools.h" #include "gnusocialapiaccount.h" #include "laconicadebug.h" #include "laconicamicroblog.h" LaconicaEditAccountWidget::LaconicaEditAccountWidget(LaconicaMicroBlog *microblog, GNUSocialApiAccount *account, QWidget *parent) : ChoqokEditAccountWidget(account, parent), mAccount(account), progress(0), isAuthenticated(false) { setupUi(this); // setAuthenticated(false); // oauthConsumerKey = "747d09d8e7b9417f5835f04510cb86ed";//Identi.ca tokens // oauthConsumerSecret = "57605f8507a041525a2d5c0abef15b20"; // connect(kcfg_authorize, SIGNAL(clicked(bool)), SLOT(authorizeUser())); // connect(kcfg_authMethod, SIGNAL(currentIndexChanged(int)), SLOT(slotAuthMethodChanged(int))); // slotAuthMethodChanged(kcfg_authMethod->currentIndex()); - connect(kcfg_host, SIGNAL(editingFinished()), SLOT(slotCheckHostUrl())); + connect(kcfg_host, &QLineEdit::editingFinished, this, + &LaconicaEditAccountWidget::slotCheckHostUrl); if (mAccount) { kcfg_alias->setText(mAccount->alias()); kcfg_host->setText(mAccount->host()); kcfg_api->setText(mAccount->api()); // kcfg_oauthUsername->setText( mAccount->username() ); kcfg_basicUsername->setText(mAccount->username()); kcfg_basicPassword->setText(mAccount->password()); kcfg_changeExclamationMark->setChecked(mAccount->isChangeExclamationMark()); kcfg_changeToString->setText(mAccount->changeExclamationMarkToText()); // if(mAccount->usingOAuth()){ // if( !mAccount->oauthConsumerKey().isEmpty() && // !mAccount->oauthConsumerSecret().isEmpty() && // !mAccount->oauthToken().isEmpty() && // !mAccount->oauthTokenSecret().isEmpty() ) { // setAuthenticated(true); // oauthConsumerKey = mAccount->oauthConsumerKey(); // oauthConsumerSecret = mAccount->oauthConsumerSecret(); // token = mAccount->oauthToken(); // tokenSecret = mAccount->oauthTokenSecret(); // } else { // setAuthenticated(false); // } // kcfg_authMethod->setCurrentIndex(0); // } else { // kcfg_authMethod->setCurrentIndex(1); // } } else { // kcfg_authMethod->setCurrentIndex(0); QString newAccountAlias = microblog->serviceName(); QString servName = newAccountAlias; int counter = 1; while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) { newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter); counter++; } setAccount(mAccount = new GNUSocialApiAccount(microblog, newAccountAlias)); kcfg_alias->setText(newAccountAlias); const QRegExp userRegExp(QLatin1String("([a-z0-9]){1,64}"), Qt::CaseInsensitive); QValidator *userVal = new QRegExpValidator(userRegExp, 0); kcfg_basicUsername->setValidator(userVal); } loadTimelinesTableState(); kcfg_alias->setFocus(Qt::OtherFocusReason); } LaconicaEditAccountWidget::~LaconicaEditAccountWidget() { } bool LaconicaEditAccountWidget::validateData() { // if( kcfg_authMethod->currentIndex()==0 ) {//OAuth // if(kcfg_alias->text().isEmpty() || kcfg_oauthUsername->text().isEmpty() || !isAuthenticated) // return false; // } else {//Basic if (kcfg_alias->text().isEmpty() || kcfg_basicUsername->text().isEmpty() || kcfg_basicPassword->text().isEmpty()) { return false; } // } return true; } Choqok::Account *LaconicaEditAccountWidget::apply() { qCDebug(CHOQOK); /*if(kcfg_authMethod->currentIndex() == 0){ mAccount->setUsername( kcfg_oauthUsername->text() ); mAccount->setOauthToken( token ); mAccount->setOauthConsumerKey( oauthConsumerKey ); mAccount->setOauthConsumerSecret( oauthConsumerSecret ); mAccount->setOauthTokenSecret( tokenSecret ); mAccount->setUsingOAuth(true); } else*/ { mAccount->setUsername(kcfg_basicUsername->text()); mAccount->setPassword(kcfg_basicPassword->text()); mAccount->setUsingOAuth(false); } mAccount->setHost(kcfg_host->text()); mAccount->setApi(kcfg_api->text()); mAccount->setAlias(kcfg_alias->text()); mAccount->setChangeExclamationMark(kcfg_changeExclamationMark->isChecked()); mAccount->setChangeExclamationMarkToText(kcfg_changeToString->text()); saveTimelinesTableState(); setTextLimit(); mAccount->writeConfig(); return mAccount; } // void LaconicaEditAccountWidget::authorizeUser() // { // qCDebug(CHOQOK); // slotCheckHostUrl(); // if(QUrl(kcfg_host->text()).host()!="identi.ca"){ // KMessageBox::sorry(this, i18n("Sorry, OAuth Method just works with Identi.ca server. You have to use basic authentication for other StatusNet servers.")); // kcfg_authMethod->setCurrentIndex(1); // return; // } // qoauth = new QOAuth::Interface(new KIO::Integration::AccessManager(this), this); // //TODO change this to have support for self hosted StatusNets // qoauth->setConsumerKey( oauthConsumerKey ); // qoauth->setConsumerSecret( oauthConsumerSecret ); // qoauth->setRequestTimeout( 10000 ); // // // send a request for an unauthorized token // QString oauthReqTokenUrl = QString("%1/%2/oauth/request_token").arg(kcfg_host->text()).arg(kcfg_api->text()); // // qCDebug(CHOQOK)<requestToken( oauthReqTokenUrl, QOAuth::GET, QOAuth::HMAC_SHA1, params ); // setAuthenticated(false); // kcfg_authorize->setIcon(QIcon::fromTheme("object-locked")); // // // if no error occurred, read the received token and token secret // if ( qoauth->error() == QOAuth::NoError ) { // token = reply.value( QOAuth::tokenParameterName() ); // tokenSecret = reply.value( QOAuth::tokenSecretParameterName() ); // qCDebug(CHOQOK)<<"token: "<text()).arg(kcfg_api->text())); // url.addQueryItem( QOAuth::tokenParameterName(), token ); // url.addQueryItem( "oauth_token", token ); // Choqok::openUrl(url); // kcfg_authorize->setEnabled(false); // getPinCode(); // } else { // qCDebug(CHOQOK)<<"ERROR:" <error()<error()); // KMessageBox::detailedError(this, i18n("Authentication Error"), // Choqok::qoauthErrorText(qoauth->error())); // } // } // // void LaconicaEditAccountWidget::getPinCode() // { // isAuthenticated = false; // while(!isAuthenticated){ // QString verifier = KInputDialog::getText( i18n("Security code"), // i18nc("Security code recieved from StatusNet", // "Enter security code:")); // if(verifier.isEmpty()) // return; // QOAuth::ParamMap otherArgs; // otherArgs.insert( "oauth_verifier", verifier.toUtf8() ); // // QOAuth::ParamMap reply = // qoauth->accessToken( QString("%1/%2/oauth/access_token").arg(kcfg_host->text()).arg(kcfg_api->text()), // QOAuth::GET, token, tokenSecret, QOAuth::HMAC_SHA1, otherArgs ); // // if no error occurred, read the Access Token (and other arguments, if applicable) // if ( qoauth->error() == QOAuth::NoError ) { // sender()->deleteLater(); // kcfg_authorize->setEnabled(true); // token = reply.value( QOAuth::tokenParameterName() ); // tokenSecret = reply.value( QOAuth::tokenSecretParameterName() ); // qCDebug(CHOQOK)<<"token: "<error()<<' '<error()); // KMessageBox::detailedError(this, i18n("Authentication Error"), // Choqok::qoauthErrorText(qoauth->error())); // } // } // } void LaconicaEditAccountWidget::setTextLimit() { QString url = mAccount->host() + QLatin1Char('/') + mAccount->api() + QLatin1String("/statusnet/config.json"); KIO::StoredTransferJob *job = KIO::storedGet(QUrl(url), KIO::Reload, KIO::HideProgressInfo); job->exec(); if (job->error()) { qCCritical(CHOQOK) << "Job error:" << job->errorString(); return; } const QJsonDocument json = QJsonDocument::fromJson(job->data()); if (!json.isNull()) { const QVariantMap siteInfos = json.toVariant().toMap()[QLatin1String("site")].toMap(); bool ok; mAccount->setPostCharLimit(siteInfos[QLatin1String("textlimit")].toUInt(&ok)); if (!ok) { qCDebug(CHOQOK) << "Cannot parse text limit value"; mAccount->setPostCharLimit(140); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } void LaconicaEditAccountWidget::loadTimelinesTableState() { for (const QString &timeline: mAccount->microblog()->timelineNames()) { int newRow = timelinesTable->rowCount(); timelinesTable->insertRow(newRow); Choqok::TimelineInfo *info = mAccount->microblog()->timelineInfo(timeline); QTableWidgetItem *item = new QTableWidgetItem(info->name); item->setData(32, timeline); item->setToolTip(info->description); timelinesTable->setItem(newRow, 0, item); QCheckBox *enable = new QCheckBox(timelinesTable); enable->setChecked(mAccount->timelineNames().contains(timeline)); timelinesTable->setCellWidget(newRow, 1, enable); } } void LaconicaEditAccountWidget::saveTimelinesTableState() { QStringList timelines; int rowCount = timelinesTable->rowCount(); for (int i = 0; i < rowCount; ++i) { QCheckBox *enable = qobject_cast(timelinesTable->cellWidget(i, 1)); if (enable && enable->isChecked()) { timelines << timelinesTable->item(i, 0)->data(32).toString(); } } timelines.removeDuplicates(); mAccount->setTimelineNames(timelines); } // void LaconicaEditAccountWidget::slotAuthMethodChanged(int index) // { // if(index == 0){ // kcfg_BasicBox->hide(); // kcfg_OAuthBox->show(); // } else { // kcfg_BasicBox->show(); // kcfg_OAuthBox->hide(); // } // } // void LaconicaEditAccountWidget::setAuthenticated(bool authenticated) // { // isAuthenticated = authenticated; // if(authenticated){ // kcfg_authorize->setIcon(QIcon::fromTheme("object-unlocked")); // kcfg_authenticateLed->on(); // kcfg_authenticateStatus->setText(i18n("Authenticated")); // } else { // kcfg_authorize->setIcon(QIcon::fromTheme("object-locked")); // kcfg_authenticateLed->off(); // kcfg_authenticateStatus->setText(i18n("Not Authenticated")); // } // } void LaconicaEditAccountWidget::slotCheckHostUrl() { if (!kcfg_host->text().isEmpty() && !kcfg_host->text().startsWith(QLatin1String("http"), Qt::CaseInsensitive) && !kcfg_host->text().startsWith(QLatin1String("https"))) { kcfg_host->setText(kcfg_host->text().prepend(QLatin1String("https://"))); } } diff --git a/microblogs/ocs/ocsaccount.cpp b/microblogs/ocs/ocsaccount.cpp index b2821cfc..693ba867 100644 --- a/microblogs/ocs/ocsaccount.cpp +++ b/microblogs/ocs/ocsaccount.cpp @@ -1,82 +1,83 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "ocsaccount.h" #include #include "ocsdebug.h" #include "ocsmicroblog.h" class OCSAccount::Private { public: QUrl providerUrl; Attica::Provider provider; OCSMicroblog *mBlog; }; OCSAccount::OCSAccount(OCSMicroblog *parent, const QString &alias) : Account(parent, alias), d(new Private) { qCDebug(CHOQOK) << alias; d->mBlog = parent; setProviderUrl(QUrl(configGroup()->readEntry("ProviderUrl", QString()))); } OCSAccount::~OCSAccount() { delete d; } void OCSAccount::writeConfig() { configGroup()->writeEntry("ProviderUrl", d->providerUrl.toString()); Choqok::Account::writeConfig(); } QUrl OCSAccount::providerUrl() const { return d->providerUrl; } void OCSAccount::setProviderUrl(const QUrl &url) { qCDebug(CHOQOK) << url; d->providerUrl = url; if (d->mBlog->isOperational()) { slotDefaultProvidersLoaded(); } else { - connect(d->mBlog, SIGNAL(initialized()), SLOT(slotDefaultProvidersLoaded())); + connect(d->mBlog, &OCSMicroblog::initialized, this, + &OCSAccount::slotDefaultProvidersLoaded); } } Attica::Provider OCSAccount::provider() { return d->provider; } void OCSAccount::slotDefaultProvidersLoaded() { d->provider = d->mBlog->providerManager()->providerByUrl(d->providerUrl); } diff --git a/microblogs/ocs/ocsconfigurewidget.cpp b/microblogs/ocs/ocsconfigurewidget.cpp index 9c0ec585..5e3a2c89 100644 --- a/microblogs/ocs/ocsconfigurewidget.cpp +++ b/microblogs/ocs/ocsconfigurewidget.cpp @@ -1,103 +1,104 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "ocsconfigurewidget.h" #include #include #include #include "accountmanager.h" #include "ocsaccount.h" #include "ocsmicroblog.h" #include "ocsdebug.h" OCSConfigureWidget::OCSConfigureWidget(OCSMicroblog *microblog, OCSAccount *account, QWidget *parent) : ChoqokEditAccountWidget(account, parent), mAccount(account), mMicroblog(microblog), providersLoaded(false) { setupUi(this); cfg_provider->setCurrentText(i18n("Loading...")); if (microblog->isOperational()) { slotprovidersLoaded(); } else { - connect(microblog, SIGNAL(initialized()), SLOT(slotprovidersLoaded())); + connect(microblog, &OCSMicroblog::initialized, this, + &OCSConfigureWidget::slotprovidersLoaded); } if (mAccount) { cfg_alias->setText(mAccount->alias()); } else { QString newAccountAlias = microblog->serviceName(); QString servName = newAccountAlias; int counter = 1; while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) { newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter); counter++; } setAccount(mAccount = new OCSAccount(microblog, newAccountAlias)); cfg_alias->setText(newAccountAlias); } } OCSConfigureWidget::~OCSConfigureWidget() { } bool OCSConfigureWidget::validateData() { if (!providersLoaded) { KMessageBox::sorry(choqokMainWindow, i18n("You have to wait for providers list to be loaded.")); return false; } if (!cfg_alias->text().isEmpty() && cfg_provider->currentIndex() >= 0) { return true; } else { return false; } } Choqok::Account *OCSConfigureWidget::apply() { mAccount->setAlias(cfg_alias->text()); mAccount->setProviderUrl(cfg_provider->itemData(cfg_provider->currentIndex()).toUrl()); mAccount->writeConfig(); return mAccount; } void OCSConfigureWidget::slotprovidersLoaded() { qCDebug(CHOQOK); cfg_provider->removeItem(0); providersLoaded = true; QList providerList = mMicroblog->providerManager()->providers(); int selectedIndex = 0; for (const Attica::Provider &p: providerList) { qCDebug(CHOQOK) << p.baseUrl(); cfg_provider->addItem(p.name(), p.baseUrl()); if (mAccount && mAccount->providerUrl() == p.baseUrl()) { selectedIndex = cfg_provider->count() - 1; } } cfg_provider->setCurrentIndex(selectedIndex); } diff --git a/microblogs/ocs/ocsmicroblog.cpp b/microblogs/ocs/ocsmicroblog.cpp index 9bb3634e..3fe390f2 100644 --- a/microblogs/ocs/ocsmicroblog.cpp +++ b/microblogs/ocs/ocsmicroblog.cpp @@ -1,310 +1,311 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "ocsmicroblog.h" #include #include #include #include #include #include "application.h" #include "accountmanager.h" #include "editaccountwidget.h" #include "postwidget.h" #include "ocsaccount.h" #include "ocsdebug.h" #include "ocsconfigurewidget.h" K_PLUGIN_FACTORY_WITH_JSON(OCSMicroblogFactory, "choqok_ocs.json", registerPlugin < OCSMicroblog > ();) OCSMicroblog::OCSMicroblog(QObject *parent, const QVariantList &) : MicroBlog(QLatin1String("choqok_ocs"), parent) , mProviderManager(new Attica::ProviderManager) , mIsOperational(false) { - connect(mProviderManager, SIGNAL(defaultProvidersLoaded()), - this, SLOT(slotDefaultProvidersLoaded())); + connect(mProviderManager, &Attica::ProviderManager::defaultProvidersLoaded, + this, &OCSMicroblog::slotDefaultProvidersLoaded); mProviderManager->loadDefaultProviders(); setServiceName(QLatin1String("Social Desktop Activities")); } OCSMicroblog::~OCSMicroblog() { delete mProviderManager; } void OCSMicroblog::saveTimeline(Choqok::Account *account, const QString &timelineName, const QList< Choqok::UI::PostWidget * > &timeline) { qCDebug(CHOQOK); QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); ///Clear previous data: for (const QString &group: postsBackup.groupList()) { postsBackup.deleteGroup(group); } for (Choqok::UI::PostWidget *wd: timeline) { const Choqok::Post *post = wd->currentPost(); KConfigGroup grp(&postsBackup, post->creationDateTime.toString()); grp.writeEntry("creationDateTime", post->creationDateTime); grp.writeEntry("postId", post->postId); grp.writeEntry("text", post->content); grp.writeEntry("authorId", post->author.userId); grp.writeEntry("authorUserName", post->author.userName); grp.writeEntry("authorRealName", post->author.realName); grp.writeEntry("authorProfileImageUrl", post->author.profileImageUrl); grp.writeEntry("authorDescription" , post->author.description); grp.writeEntry("authorLocation" , post->author.location); grp.writeEntry("authorUrl" , post->author.homePageUrl); grp.writeEntry("link", post->link); grp.writeEntry("isRead" , post->isRead); } postsBackup.sync(); if (Choqok::Application::isShuttingDown()) { Q_EMIT readyForUnload(); } } QList< Choqok::Post * > OCSMicroblog::loadTimeline(Choqok::Account *account, const QString &timelineName) { qCDebug(CHOQOK) << timelineName; QList< Choqok::Post * > list; QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); QStringList tmpList = postsBackup.groupList(); QList groupList; for (const QString &str: tmpList) { groupList.append(QDateTime::fromString(str)); } qSort(groupList); int count = groupList.count(); if (count) { Choqok::Post *st = 0; for (int i = 0; i < count; ++i) { st = new Choqok::Post; KConfigGroup grp(&postsBackup, groupList[i].toString()); st->creationDateTime = grp.readEntry("creationDateTime", QDateTime::currentDateTime()); st->postId = grp.readEntry("postId", QString()); st->content = grp.readEntry("text", QString()); st->author.userId = grp.readEntry("authorId", QString()); st->author.userName = grp.readEntry("authorUserName", QString()); st->author.realName = grp.readEntry("authorRealName", QString()); st->author.profileImageUrl = grp.readEntry("authorProfileImageUrl", QUrl()); st->author.description = grp.readEntry("authorDescription" , QString()); st->author.location = grp.readEntry("authorLocation", QString()); st->author.homePageUrl = grp.readEntry("authorUrl", QUrl()); st->link = grp.readEntry("link", QUrl()); st->isRead = grp.readEntry("isRead", true); list.append(st); } } return list; } Choqok::Account *OCSMicroblog::createNewAccount(const QString &alias) { OCSAccount *acc = qobject_cast(Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return new OCSAccount(this, alias); } else { return 0;//If there's an account with this alias, So We can't create a new one } } ChoqokEditAccountWidget *OCSMicroblog::createEditAccountWidget(Choqok::Account *account, QWidget *parent) { qCDebug(CHOQOK); OCSAccount *acc = qobject_cast(account); if (acc || !account) { return new OCSConfigureWidget(this, acc, parent); } else { qCDebug(CHOQOK) << "Account passed here was not a valid OCSAccount!"; return nullptr; } } void OCSMicroblog::createPost(Choqok::Account *theAccount, Choqok::Post *post) { if (!mIsOperational) { Q_EMIT errorPost(theAccount, post, OtherError, i18n("OCS plugin is not initialized yet. Try again later.")); return; } qCDebug(CHOQOK); OCSAccount *acc = qobject_cast(theAccount); Attica::PostJob *job = acc->provider().postActivity(post->content); mJobsAccount.insert(job, acc); mJobsPost.insert(job, post); - connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(slotCreatePost(Attica::BaseJob*))); + connect(job, &Attica::PostJob::finished, this, + &OCSMicroblog::slotCreatePost); job->start(); } void OCSMicroblog::slotCreatePost(Attica::BaseJob *job) { OCSAccount *acc = mJobsAccount.take(job); Choqok::Post *post = mJobsPost.take(job); Q_EMIT postCreated(acc, post); } void OCSMicroblog::abortCreatePost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); Q_UNUSED(post); OCSAccount *acc = qobject_cast(theAccount); Attica::BaseJob *job = mJobsAccount.key(acc); if (job) { job->abort(); } } void OCSMicroblog::fetchPost(Choqok::Account *theAccount, Choqok::Post *post) { Q_UNUSED(theAccount); Q_UNUSED(post); KMessageBox::sorry(choqokMainWindow, i18n("Not Supported")); } void OCSMicroblog::removePost(Choqok::Account *theAccount, Choqok::Post *post) { Q_UNUSED(theAccount); Q_UNUSED(post); KMessageBox::sorry(choqokMainWindow, i18n("Not Supported")); } Attica::ProviderManager *OCSMicroblog::providerManager() { return mProviderManager; } void OCSMicroblog::updateTimelines(Choqok::Account *theAccount) { if (!mIsOperational) { scheduledTasks.insertMulti(theAccount, Update); return; } qCDebug(CHOQOK); OCSAccount *acc = qobject_cast(theAccount); if (!acc) { qCCritical(CHOQOK) << "OCSMicroblog::updateTimelines: acc is not an OCSAccount"; return; } Attica::ListJob *job = acc->provider().requestActivities(); mJobsAccount.insert(job, acc); - connect(job, SIGNAL(finished(Attica::BaseJob*)), SLOT(slotTimelineLoaded(Attica::BaseJob*))); + connect(job, &Attica::BaseJob::finished, this, &OCSMicroblog::slotTimelineLoaded); job->start(); } void OCSMicroblog::slotTimelineLoaded(Attica::BaseJob *job) { qCDebug(CHOQOK); OCSAccount *acc = mJobsAccount.take(job); if (job->metadata().error() == Attica::Metadata::NoError) { Attica::Activity::List actList = static_cast< Attica::ListJob * >(job)->itemList(); Q_EMIT timelineDataReceived(acc, QLatin1String("Activity"), parseActivityList(actList)); } else { Q_EMIT error(acc, ServerError, job->metadata().message(), Low); } } QList< Choqok::Post * > OCSMicroblog::parseActivityList(const Attica::Activity::List &list) { qCDebug(CHOQOK) << list.count(); QList< Choqok::Post * > resultList; for (const Attica::Activity &act: list) { Choqok::Post *pst = new Choqok::Post; pst->postId = act.id(); pst->content = act.message(); pst->creationDateTime = act.timestamp(); pst->link = act.link(); pst->isError = !act.isValid(); pst->author.userId = act.associatedPerson().id(); pst->author.userName = act.associatedPerson().id(); pst->author.homePageUrl = QUrl::fromUserInput(act.associatedPerson().homepage()); pst->author.location = QStringLiteral("%1(%2)").arg(act.associatedPerson().country()) .arg(act.associatedPerson().city()); pst->author.profileImageUrl = act.associatedPerson().avatarUrl(); pst->author.realName = QStringLiteral("%1 %2").arg(act.associatedPerson().firstName()) .arg(act.associatedPerson().lastName()); resultList.insert(0, pst); } return resultList; } Choqok::TimelineInfo *OCSMicroblog::timelineInfo(const QString &timelineName) { if (timelineName == QLatin1String("Activity")) { Choqok::TimelineInfo *info = new Choqok::TimelineInfo; info->name = i18nc("Timeline Name", "Activity"); info->description = i18n("Social activities"); info->icon = QLatin1String("user-home"); return info; } else { qCCritical(CHOQOK) << "timelineName is not valid!"; return 0; } } bool OCSMicroblog::isOperational() { return mIsOperational; } void OCSMicroblog::slotDefaultProvidersLoaded() { qCDebug(CHOQOK); mIsOperational = true; Q_EMIT initialized(); for (Choqok::Account *acc: scheduledTasks.keys()) { switch (scheduledTasks.value(acc)) { case Update: updateTimelines(acc); break; default: break; }; } } QUrl OCSMicroblog::profileUrl(Choqok::Account *account, const QString &username) const { OCSAccount *acc = qobject_cast(account); if (acc->providerUrl().host().contains(QLatin1String("opendesktop.org"))) { return QUrl::fromUserInput(QStringLiteral("https://opendesktop.org/usermanager/search.php?username=%1").arg(username)); } return QUrl(); } void OCSMicroblog::aboutToUnload() { Q_EMIT saveTimelines(); } #include "ocsmicroblog.moc" diff --git a/microblogs/pumpio/pumpiocomposerwidget.cpp b/microblogs/pumpio/pumpiocomposerwidget.cpp index 1f40ec73..ae2b15bb 100644 --- a/microblogs/pumpio/pumpiocomposerwidget.cpp +++ b/microblogs/pumpio/pumpiocomposerwidget.cpp @@ -1,190 +1,186 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013-2014 Andrea Scarpino Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiocomposerwidget.h" #include #include #include #include #include #include #include #include "account.h" #include "choqoktextedit.h" #include "shortenmanager.h" #include "pumpiodebug.h" #include "pumpiomicroblog.h" #include "pumpiopost.h" class PumpIOComposerWidget::Private { public: QString mediumToAttach; QPushButton *btnAttach; QPointer mediumName; QPointer btnCancel; QGridLayout *editorLayout; QString replyToObjectType; }; PumpIOComposerWidget::PumpIOComposerWidget(Choqok::Account *account, QWidget *parent) : ComposerWidget(account, parent) , d(new Private) { d->editorLayout = qobject_cast(editorContainer()->layout()); d->btnAttach = new QPushButton(editorContainer()); d->btnAttach->setIcon(QIcon::fromTheme(QLatin1String("mail-attachment"))); d->btnAttach->setToolTip(i18n("Attach a file")); d->btnAttach->setMaximumWidth(d->btnAttach->height()); - connect(d->btnAttach, SIGNAL(clicked(bool)), this, SLOT(attachMedia())); + connect(d->btnAttach, &QPushButton::clicked, this, &PumpIOComposerWidget::attachMedia); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(d->btnAttach); vLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding)); d->editorLayout->addItem(vLayout, 0, 1); } PumpIOComposerWidget::~PumpIOComposerWidget() { delete d; } void PumpIOComposerWidget::submitPost(const QString &text) { qCDebug(CHOQOK); editorContainer()->setEnabled(false); QString txt = text; if (currentAccount()->postCharLimit() && txt.size() > (int) currentAccount()->postCharLimit()) { txt = Choqok::ShortenManager::self()->parseText(txt); } setPostToSubmit(nullptr); setPostToSubmit(new Choqok::Post); postToSubmit()->content = txt; if (!replyToId.isEmpty()) { postToSubmit()->replyToPostId = replyToId; } - connect(currentAccount()->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotPostSubmited(Choqok::Account*,Choqok::Post*))); - connect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), this, - SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, this, + &PumpIOComposerWidget::slotPostSubmited); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, this, + &PumpIOComposerWidget::slotErrorPost); btnAbort = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("Abort"), this); layout()->addWidget(btnAbort); - connect(btnAbort, SIGNAL(clicked(bool)), SLOT(abort())); + connect(btnAbort, &QPushButton::clicked, this, &PumpIOComposerWidget::abort); PumpIOMicroBlog *mBlog = qobject_cast(currentAccount()->microblog()); if (d->mediumToAttach.isEmpty()) { if (replyToId.isEmpty()) { currentAccount()->microblog()->createPost(currentAccount(), postToSubmit()); } else { // WTF? It seems we cannot cast postToSubmit to PumpIOPost and then I'm copying its attributes PumpIOPost *pumpPost = new PumpIOPost(); pumpPost->content = postToSubmit()->content; pumpPost->replyToPostId = postToSubmit()->replyToPostId; pumpPost->replyToObjectType = d->replyToObjectType; setPostToSubmit(pumpPost); mBlog->createReply(currentAccount(), pumpPost); } } else { mBlog->createPostWithMedia(currentAccount(), postToSubmit(), d->mediumToAttach); } } void PumpIOComposerWidget::slotPostSubmited(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (currentAccount() == theAccount && post == postToSubmit()) { qCDebug(CHOQOK) << "Accepted"; - disconnect(currentAccount()->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotPostSubmited(Choqok::Account*,Choqok::Post*))); - disconnect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, + this, &PumpIOComposerWidget::slotPostSubmited); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, + this, &PumpIOComposerWidget::slotErrorPost); if (btnAbort) { btnAbort->deleteLater(); } editor()->clear(); editorCleared(); editorContainer()->setEnabled(true); setPostToSubmit(nullptr); cancelAttach(); currentAccount()->microblog()->updateTimelines(currentAccount()); } } void PumpIOComposerWidget::attachMedia() { qCDebug(CHOQOK); d->mediumToAttach = QFileDialog::getOpenFileName(this, i18n("Select Media to Upload"), QString(), QStringLiteral("Images")); if (d->mediumToAttach.isEmpty()) { qCDebug(CHOQOK) << "No file selected"; return; } const QString fileName = QUrl(d->mediumToAttach).fileName(); if (!d->mediumName) { d->mediumName = new QLabel(editorContainer()); d->btnCancel = new QPushButton(editorContainer()); d->btnCancel->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->btnCancel->setToolTip(i18n("Discard Attachment")); d->btnCancel->setMaximumWidth(d->btnCancel->height()); - connect(d->btnCancel, SIGNAL(clicked(bool)), SLOT(cancelAttach())); + connect(d->btnCancel, &QPushButton::clicked, this, &PumpIOComposerWidget::cancelAttach); d->editorLayout->addWidget(d->mediumName, 1, 0); d->editorLayout->addWidget(d->btnCancel, 1, 1); } d->mediumName->setText(i18n("Attaching %1", fileName)); editor()->setFocus(); } void PumpIOComposerWidget::cancelAttach() { qCDebug(CHOQOK); delete d->mediumName; d->mediumName = 0; delete d->btnCancel; d->btnCancel = 0; d->mediumToAttach.clear(); } void PumpIOComposerWidget::slotSetReply(const QString replyToId, const QString replyToUsername, const QString replyToObjectType) { qCDebug(CHOQOK); this->replyToId = replyToId; this->replyToUsername = replyToUsername; d->replyToObjectType = replyToObjectType; if (!replyToUsername.isEmpty()) { replyToUsernameLabel()->setText(i18n("Replying to %1", replyToUsername)); btnCancelReply()->show(); replyToUsernameLabel()->show(); } editor()->setFocus(); } diff --git a/microblogs/pumpio/pumpiocomposerwidget.h b/microblogs/pumpio/pumpiocomposerwidget.h index 13c9c1c4..90ee853c 100644 --- a/microblogs/pumpio/pumpiocomposerwidget.h +++ b/microblogs/pumpio/pumpiocomposerwidget.h @@ -1,49 +1,51 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013-2014 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #ifndef PUMPIOCOMPOSERWIDGET_H #define PUMPIOCOMPOSERWIDGET_H #include "composerwidget.h" class PumpIOComposerWidget : public Choqok::UI::ComposerWidget { Q_OBJECT public: explicit PumpIOComposerWidget(Choqok::Account *account, QWidget *parent = 0); ~PumpIOComposerWidget(); +public Q_SLOTS: + void slotSetReply(const QString replyToId, const QString replyToUsername, const QString replyToObjectType); + protected Q_SLOTS: virtual void submitPost(const QString &text) override; virtual void slotPostSubmited(Choqok::Account *theAccount, Choqok::Post *post) override; - void slotSetReply(const QString replyToId, const QString replyToUsername, const QString replyToObjectType); void cancelAttach(); void attachMedia(); private: class Private; Private *const d; }; -#endif // PUMPIOCOMPOSERWIDGET_H \ No newline at end of file +#endif // PUMPIOCOMPOSERWIDGET_H diff --git a/microblogs/pumpio/pumpioeditaccountwidget.cpp b/microblogs/pumpio/pumpioeditaccountwidget.cpp index 5743df8e..cf51e311 100644 --- a/microblogs/pumpio/pumpioeditaccountwidget.cpp +++ b/microblogs/pumpio/pumpioeditaccountwidget.cpp @@ -1,220 +1,221 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpioeditaccountwidget.h" #include #include #include #include +#include #include #include #include #include #include "choqoktools.h" #include "accountmanager.h" #include "pumpioaccount.h" #include "pumpiodebug.h" #include "pumpiomicroblog.h" #include "pumpiooauth.h" PumpIOEditAccountWidget::PumpIOEditAccountWidget(PumpIOMicroBlog *microblog, PumpIOAccount *account, QWidget *parent): ChoqokEditAccountWidget(account, parent) , m_account(account) { setupUi(this); - connect(kcfg_authorize, SIGNAL(clicked(bool)), SLOT(authorizeUser())); + connect(kcfg_authorize, &QPushButton::clicked, this, &PumpIOEditAccountWidget::authorizeUser); if (m_account) { kcfg_alias->setText(m_account->alias()); kcfg_webfingerid->setText(m_account->webfingerID()); setAuthenticated(!m_account->token().isEmpty() && !m_account->tokenSecret().isEmpty()); } else { setAuthenticated(false); QString newAccountAlias = microblog->serviceName(); const QString servName = newAccountAlias; int counter = 1; while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) { newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter); counter++; } m_account = new PumpIOAccount(microblog, newAccountAlias); setAccount(m_account); kcfg_alias->setText(newAccountAlias); } loadTimelinesTable(); } PumpIOEditAccountWidget::~PumpIOEditAccountWidget() { } Choqok::Account *PumpIOEditAccountWidget::apply() { m_account->setAlias(kcfg_alias->text()); m_account->setUsername(kcfg_webfingerid->text().split(QLatin1Char('@'))[0]); m_account->setToken(m_account->oAuth()->token()); m_account->setTokenSecret(m_account->oAuth()->tokenSecret()); m_account->writeConfig(); saveTimelinesTable(); return m_account; } void PumpIOEditAccountWidget::authorizeUser() { qCDebug(CHOQOK); if (kcfg_webfingerid->text().isEmpty() || !kcfg_webfingerid->text().contains(QLatin1Char('@'))) { return; } if (m_account->consumerKey().isEmpty() || m_account->consumerSecret().isEmpty()) { registerClient(); } m_account->oAuth()->grant(); connect(m_account->oAuth(), &QAbstractOAuth::authorizeWithBrowser, &Choqok::openUrl); connect(m_account->oAuth(), &QAbstractOAuth::statusChanged, this, &PumpIOEditAccountWidget::getPinCode); } void PumpIOEditAccountWidget::getPinCode() { isAuthenticated = false; if (m_account->oAuth()->status() == QAbstractOAuth::Status::TemporaryCredentialsReceived) { QString verifier = QInputDialog::getText(this, i18n("PIN"), i18n("Enter the verifier code received from %1", m_account->host())); if (verifier.isEmpty()) { return; } m_account->oAuth()->continueGrantWithVerifier(verifier); } else if (m_account->oAuth()->status() == QAbstractOAuth::Status::Granted) { setAuthenticated(true); KMessageBox::information(this, i18n("Choqok is authorized successfully."), i18n("Authorized")); } else { KMessageBox::detailedError(this, i18n("Authorization Error"), i18n("OAuth authorization error")); } } bool PumpIOEditAccountWidget::validateData() { if (kcfg_alias->text().isEmpty() || kcfg_webfingerid->text().isEmpty() || !kcfg_webfingerid->text().contains(QLatin1Char('@')) || !isAuthenticated) { return false; } else { return true; } } void PumpIOEditAccountWidget::setAuthenticated(bool authenticated) { isAuthenticated = authenticated; if (authenticated) { kcfg_authorize->setIcon(QIcon::fromTheme(QLatin1String("object-unlocked"))); kcfg_authenticateLed->on(); kcfg_authenticateStatus->setText(i18n("Authenticated")); } else { kcfg_authorize->setIcon(QIcon::fromTheme(QLatin1String("object-locked"))); kcfg_authenticateLed->off(); kcfg_authenticateStatus->setText(i18n("Not Authenticated")); } } void PumpIOEditAccountWidget::loadTimelinesTable() { for (const QString &timeline: m_account->microblog()->timelineNames()) { int newRow = timelinesTable->rowCount(); timelinesTable->insertRow(newRow); timelinesTable->setItem(newRow, 0, new QTableWidgetItem(timeline)); QCheckBox *enable = new QCheckBox(timelinesTable); enable->setChecked(m_account->timelineNames().contains(timeline)); timelinesTable->setCellWidget(newRow, 1, enable); } } void PumpIOEditAccountWidget::registerClient() { if (kcfg_webfingerid->text().contains(QLatin1Char('@'))) { m_account->setHost(QLatin1String("https://") + kcfg_webfingerid->text().split(QLatin1Char('@'))[1]); m_account->oAuth()->setTemporaryCredentialsUrl(QUrl(m_account->host() + QLatin1String("/oauth/request_token"))); m_account->oAuth()->setAuthorizationUrl(QUrl(m_account->host() + QLatin1String("/oauth/authorize"))); m_account->oAuth()->setTokenCredentialsUrl(QUrl(m_account->host() + QLatin1String("/oauth/access_token"))); QUrl url(m_account->host() + QLatin1String("/api/client/register")); QByteArray data("{" " \"type\": \"client_associate\", " " \"application_type\": \"native\", " " \"application_name\": \"Choqok\" " "}"); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); QEventLoop loop; - connect(job, SIGNAL(result(KJob*)), &loop, SLOT(quit())); + connect(job, &KIO::StoredTransferJob::result, &loop, &QEventLoop::quit); job->start(); loop.exec(); if (job->error()) { qCDebug(CHOQOK) << "An error occurred in Job"; return; } else { KIO::StoredTransferJob *stj = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(stj->data()); if (!json.isNull()) { const QVariantMap result = json.toVariant().toMap(); m_account->setConsumerKey(result[QLatin1String("client_id")].toString()); m_account->setConsumerSecret(result[QLatin1String("client_secret")].toString()); m_account->oAuth()->setClientIdentifier(m_account->consumerKey()); m_account->oAuth()->setClientSharedSecret(m_account->consumerSecret()); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } } else { qCDebug(CHOQOK) << "webfingerID is not valid"; } } void PumpIOEditAccountWidget::saveTimelinesTable() { QStringList timelines; for (int i = 0; i < timelinesTable->rowCount(); ++i) { QCheckBox *enable = qobject_cast(timelinesTable->cellWidget(i, 1)); if (enable && enable->isChecked()) { timelines.append(timelinesTable->item(i, 0)->text()); } } m_account->setTimelineNames(timelines); } diff --git a/microblogs/pumpio/pumpiomessagedialog.cpp b/microblogs/pumpio/pumpiomessagedialog.cpp index c2935415..7c6893f1 100644 --- a/microblogs/pumpio/pumpiomessagedialog.cpp +++ b/microblogs/pumpio/pumpiomessagedialog.cpp @@ -1,213 +1,213 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013-2014 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiomessagedialog.h" #include #include #include #include #include "pumpioaccount.h" #include "pumpiodebug.h" #include "pumpiomicroblog.h" #include "pumpiopost.h" class PumpIOMessageDialog::Private { public: Choqok::Account *account; QString mediumToAttach; QPointer mediumName; QPointer btnCancel; }; PumpIOMessageDialog::PumpIOMessageDialog(Choqok::Account *theAccount, QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags) , d(new Private) { d->account = theAccount; setupUi(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &PumpIOMessageDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &PumpIOMessageDialog::reject); verticalLayout->addWidget(buttonBox); PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { for (const QVariant &list: acc->lists()) { QVariantMap l = list.toMap(); QListWidgetItem *item = new QListWidgetItem; item->setText(l.value(QLatin1String("name")).toString()); item->setData(Qt::UserRole, l.value(QLatin1String("id")).toString()); toList->addItem(item); ccList->addItem(item->clone()); } //Lists are not sorted toList->sortItems(); ccList->sortItems(); for (const QString &username: acc->following()) { QListWidgetItem *item = new QListWidgetItem; item->setText(PumpIOMicroBlog::userNameFromAcct(username)); item->setData(Qt::UserRole, username); toList->addItem(item); ccList->addItem(item->clone()); } } - connect(btnReload, SIGNAL(clicked(bool)), this, SLOT(fetchFollowing())); - connect(btnAttach, SIGNAL(clicked(bool)), this, SLOT(attachMedia())); + connect(btnReload, &QPushButton::clicked, this, &PumpIOMessageDialog::fetchFollowing); + connect(btnAttach, &QPushButton::clicked, this, &PumpIOMessageDialog::attachMedia); } PumpIOMessageDialog::~PumpIOMessageDialog() { delete d; } void PumpIOMessageDialog::fetchFollowing() { qCDebug(CHOQOK); toList->clear(); ccList->clear(); PumpIOMicroBlog *microblog = qobject_cast(d->account->microblog()); if (microblog) { microblog->fetchFollowing(d->account); - connect(microblog, SIGNAL(followingFetched(Choqok::Account*)), this, - SLOT(slotFetchFollowing(Choqok::Account*))); + connect(microblog, &PumpIOMicroBlog::followingFetched, this, + &PumpIOMessageDialog::slotFetchFollowing); } } void PumpIOMessageDialog::slotFetchFollowing(Choqok::Account *theAccount) { qCDebug(CHOQOK); if (theAccount == d->account) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { for (const QVariant &list: acc->lists()) { QVariantMap l = list.toMap(); QListWidgetItem *item = new QListWidgetItem; item->setText(l.value(QLatin1String("name")).toString()); item->setData(Qt::UserRole, l.value(QLatin1String("id")).toString()); toList->addItem(item); ccList->addItem(item->clone()); } toList->sortItems(); ccList->sortItems(); for (const QString &username: acc->following()) { QListWidgetItem *item = new QListWidgetItem; item->setText(PumpIOMicroBlog::userNameFromAcct(username)); item->setData(Qt::UserRole, username); toList->addItem(item); ccList->addItem(item->clone()); } } } } void PumpIOMessageDialog::accept() { qCDebug(CHOQOK); PumpIOAccount *acc = qobject_cast(d->account); if (acc) { if (acc->following().isEmpty() || txtMessage->toPlainText().isEmpty() || (toList->selectedItems().isEmpty() && ccList->selectedItems().isEmpty())) { return; } hide(); PumpIOMicroBlog *microblog = qobject_cast(d->account->microblog()); if (microblog) { PumpIOPost *post = new PumpIOPost; post->content = txtMessage->toPlainText(); QVariantList to; for (QListWidgetItem *item: toList->selectedItems()) { QVariantMap user; QString id = item->data(Qt::UserRole).toString(); if (id.contains(QLatin1String("acct:"))) { user.insert(QLatin1String("objectType"), QLatin1String("person")); } else { user.insert(QLatin1String("objectType"), QLatin1String("collection")); } user.insert(QLatin1String("id"), id); to.append(user); } QVariantList cc; for (QListWidgetItem *item: ccList->selectedItems()) { QVariantMap user; QString id = item->data(Qt::UserRole).toString(); if (id.contains(QLatin1String("acct:"))) { user.insert(QLatin1String("objectType"), QLatin1String("person")); } else { user.insert(QLatin1String("objectType"), QLatin1String("collection")); } user.insert(QLatin1String("id"), id); cc.append(user); } microblog->createPost(acc, post, to, cc); } } } void PumpIOMessageDialog::attachMedia() { qCDebug(CHOQOK); d->mediumToAttach = QFileDialog::getOpenFileName(this, i18n("Select Media to Upload"), QString(), QStringLiteral("Images")); if (d->mediumToAttach.isEmpty()) { qCDebug(CHOQOK) << "No file selected"; return; } const QString fileName = QUrl(d->mediumToAttach).fileName(); if (!d->mediumName) { d->mediumName = new QLabel(this); d->btnCancel = new QPushButton(this); d->btnCancel->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->btnCancel->setToolTip(i18n("Discard Attachment")); d->btnCancel->setMaximumWidth(d->btnCancel->height()); - connect(d->btnCancel, SIGNAL(clicked(bool)), SLOT(cancelAttach())); + connect(d->btnCancel, &QPushButton::clicked, this, &PumpIOMessageDialog::cancelAttach); horizontalLayout->insertWidget(1, d->mediumName); horizontalLayout->insertWidget(2, d->btnCancel); } d->mediumName->setText(i18n("Attaching %1", fileName)); txtMessage->setFocus(); } void PumpIOMessageDialog::cancelAttach() { qCDebug(CHOQOK); delete d->mediumName; d->mediumName = 0; delete d->btnCancel; d->btnCancel = 0; d->mediumToAttach.clear(); } diff --git a/microblogs/pumpio/pumpiomicroblog.cpp b/microblogs/pumpio/pumpiomicroblog.cpp index 9dcecc9d..bd12cb63 100644 --- a/microblogs/pumpio/pumpiomicroblog.cpp +++ b/microblogs/pumpio/pumpiomicroblog.cpp @@ -1,1357 +1,1357 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013-2014 Andrea Scarpino Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiomicroblog.h" #include #include #include #include #include #include #include #include #include "accountmanager.h" #include "application.h" #include "choqokbehaviorsettings.h" #include "notifymanager.h" #include "pumpioaccount.h" #include "pumpiocomposerwidget.h" #include "pumpiodebug.h" #include "pumpioeditaccountwidget.h" #include "pumpiomessagedialog.h" #include "pumpiomicroblogwidget.h" #include "pumpiopost.h" #include "pumpiopostwidget.h" class PumpIOMicroBlog::Private { public: Private(): countOfTimelinesToSave(0) {} int countOfTimelinesToSave; }; K_PLUGIN_FACTORY_WITH_JSON(PumpIOMicroBlogFactory, "choqok_pumpio.json", registerPlugin < PumpIOMicroBlog > ();) const QString PumpIOMicroBlog::inboxActivity(QLatin1String("/api/user/%1/inbox")); const QString PumpIOMicroBlog::outboxActivity(QLatin1String("/api/user/%1/feed")); const QString PumpIOMicroBlog::PublicCollection(QLatin1String("http://activityschema.org/collection/public")); PumpIOMicroBlog::PumpIOMicroBlog(QObject *parent, const QVariantList &args): MicroBlog(QStringLiteral("Pump.IO") , parent), d(new Private) { Q_UNUSED(args) setServiceName(QLatin1String("Pump.io")); setServiceHomepageUrl(QLatin1String("http://pump.io")); QStringList timelineNames; timelineNames << QLatin1String("Activity") << QLatin1String("Favorites") << QLatin1String("Inbox") << QLatin1String("Outbox"); setTimelineNames(timelineNames); setTimelinesInfo(); } PumpIOMicroBlog::~PumpIOMicroBlog() { qDeleteAll(m_timelinesInfos); delete d; } void PumpIOMicroBlog::abortAllJobs(Choqok::Account *theAccount) { for (KJob *job: m_accountJobs.keys(theAccount)) { job->kill(KJob::EmitResult); } } void PumpIOMicroBlog::abortCreatePost(Choqok::Account *theAccount, Choqok::Post *post) { if (m_createPostJobs.isEmpty()) { return; } if (post) { m_createPostJobs.key(post)->kill(KJob::EmitResult); return; } for (KJob *job: m_createPostJobs.keys()) { if (m_accountJobs[job] == theAccount) { job->kill(KJob::EmitResult); } } } void PumpIOMicroBlog::aboutToUnload() { for (Choqok::Account *acc: Choqok::AccountManager::self()->accounts()) { if (acc->microblog() == this) { d->countOfTimelinesToSave += acc->timelineNames().count(); } } Q_EMIT saveTimelines(); } QMenu *PumpIOMicroBlog::createActionsMenu(Choqok::Account *theAccount, QWidget *parent) { QMenu *menu = MicroBlog::createActionsMenu(theAccount, parent); QAction *directMessge = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18n("Send Private Message..."), menu); directMessge->setData(theAccount->alias()); - connect(directMessge, SIGNAL(triggered(bool)), this, SLOT(showDirectMessageDialog())); + connect(directMessge, &QAction::triggered, this, &PumpIOMicroBlog::showDirectMessageDialog); menu->addAction(directMessge); return menu; } Choqok::UI::MicroBlogWidget *PumpIOMicroBlog::createMicroBlogWidget(Choqok::Account *account, QWidget *parent) { return new PumpIOMicroBlogWidget(account, parent); } Choqok::UI::ComposerWidget *PumpIOMicroBlog::createComposerWidget(Choqok::Account *account, QWidget *parent) { return new PumpIOComposerWidget(account, parent); } ChoqokEditAccountWidget *PumpIOMicroBlog::createEditAccountWidget(Choqok::Account *account, QWidget *parent) { PumpIOAccount *acc = qobject_cast(account); if (acc || !account) { return new PumpIOEditAccountWidget(this, acc, parent); } else { qCDebug(CHOQOK) << "Account passed here was not a valid PumpIOAccount!"; return 0; } } Choqok::Account *PumpIOMicroBlog::createNewAccount(const QString &alias) { PumpIOAccount *acc = qobject_cast( Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return new PumpIOAccount(this, alias); } else { qCDebug(CHOQOK) << "Cannot create a new PumpIOAccount!"; return 0; } } void PumpIOMicroBlog::createPost(Choqok::Account *theAccount, Choqok::Post *post) { QVariantList to; QVariantMap thePublic; thePublic.insert(QLatin1String("objectType"), QLatin1String("collection")); thePublic.insert(QLatin1String("id"), PumpIOMicroBlog::PublicCollection); to.append(thePublic); createPost(theAccount, post, to); } void PumpIOMicroBlog::createPost(Choqok::Account *theAccount, Choqok::Post *post, const QVariantList &to, const QVariantList &cc) { if (!post || post->content.isEmpty()) { qCDebug(CHOQOK) << "ERROR: Status text is empty!"; Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::OtherError, i18n("Creating the new post failed. Text is empty."), MicroBlog::Critical); return; } PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; if (!post->postId.isEmpty()) { object.insert(QLatin1String("id"), post->postId); } if (post->type.isEmpty()) { post->type = QLatin1String("note"); } object.insert(QLatin1String("objectType"), post->type); //Convert URLs to href form post->content.replace(QRegExp(QLatin1String("((?:https?|ftp)://\\S+)")), QLatin1String("\\1")); object.insert(QLatin1String("content"), QUrl::toPercentEncoding(post->content)); QVariantMap item; item.insert(QLatin1String("verb"), QLatin1String("post")); item.insert(QLatin1String("object"), object); item.insert(QLatin1String("to"), to); item.insert(QLatin1String("cc"), cc); const QByteArray data = QJsonDocument::fromVariant(item).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + outboxActivity.arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_createPostJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotCreatePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::createReply(Choqok::Account *theAccount, PumpIOPost *post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { post->type = QLatin1String("comment"); QVariantMap object; object.insert(QLatin1String("objectType"), post->type); //Convert URLs to href form post->content.replace(QRegExp(QLatin1String("((?:https?|ftp)://\\S+)")), QLatin1String("\\1")); object.insert(QLatin1String("content"), QUrl::toPercentEncoding(post->content)); if (!post->replyToPostId.isEmpty()) { QVariantMap inReplyTo; inReplyTo.insert(QLatin1String("id"), post->replyToPostId); inReplyTo.insert(QLatin1String("objectType"), post->replyToObjectType); object.insert(QLatin1String("inReplyTo"), inReplyTo); } QVariantMap item; item.insert(QLatin1String("verb"), QLatin1String("post")); item.insert(QLatin1String("object"), object); const QByteArray data = QJsonDocument::fromVariant(item).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + outboxActivity.arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_createPostJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotCreatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotCreatePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::createPostWithMedia(Choqok::Account *theAccount, Choqok::Post *post, const QString &filePath) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QFile media(filePath); QByteArray data; if (media.open(QIODevice::ReadOnly)) { data = media.readAll(); media.close(); } else { qCDebug(CHOQOK) << "Cannot read the file"; return; } const QMimeDatabase db; const QMimeType mimetype = db.mimeTypeForFileNameAndData(filePath, data); const QString mime = mimetype.name(); if (mime == QLatin1String("application/octet-stream")) { qCDebug(CHOQOK) << "Cannot retrieve file mimetype"; return; } QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/api/user/%1/uploads").arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: ") + mime); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_uploadJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotUpload(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotUpload); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } Choqok::UI::PostWidget *PumpIOMicroBlog::createPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) { return new PumpIOPostWidget(account, post, parent); } void PumpIOMicroBlog::fetchPost(Choqok::Account *theAccount, Choqok::Post *post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { if (!post->link.toDisplayString().startsWith(acc->host())) { qCDebug(CHOQOK) << "You can only fetch posts from your host!"; return; } QUrl url(post->link); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::GetOperation)); m_accountJobs[job] = acc; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchPost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotFetchPost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::removePost(Choqok::Account *theAccount, Choqok::Post *post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert(QLatin1String("id"), post->postId); object.insert(QLatin1String("objectType"), post->type); QVariantMap item; item.insert(QLatin1String("verb"), QLatin1String("delete")); item.insert(QLatin1String("object"), object); const QByteArray data = QJsonDocument::fromVariant(item).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + outboxActivity.arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_removePostJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRemovePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotRemovePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } QList< Choqok::Post * > PumpIOMicroBlog::loadTimeline(Choqok::Account *account, const QString &timelineName) { QList< Choqok::Post * > list; const QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); const KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); const QStringList tmpList = postsBackup.groupList(); // don't load old archives if (tmpList.isEmpty() || !(QDateTime::fromString(tmpList.first()).isValid())) { return list; } QList groupList; for (const QString &str: tmpList) { groupList.append(QDateTime::fromString(str)); } qSort(groupList); PumpIOPost *st; for (const QDateTime &datetime: groupList) { st = new PumpIOPost; KConfigGroup grp(&postsBackup, datetime.toString()); st->creationDateTime = grp.readEntry("creationDateTime", QDateTime::currentDateTime()); st->postId = grp.readEntry("postId", QString()); st->link = grp.readEntry("link", QUrl()); st->content = grp.readEntry("content", QString()); st->source = grp.readEntry("source", QString()); st->isFavorited = grp.readEntry("favorited", false); st->author.userId = grp.readEntry("authorId", QString()); st->author.userName = grp.readEntry("authorUserName", QString()); st->author.realName = grp.readEntry("authorRealName", QString()); st->author.location = grp.readEntry("authorLocation", QString()); st->author.description = grp.readEntry("authorDescription" , QString()); st->author.profileImageUrl = grp.readEntry("authorProfileImageUrl", QUrl()); st->author.homePageUrl = grp.readEntry("authorHomePageUrl", QUrl()); st->type = grp.readEntry("type", QString()); st->media = grp.readEntry("media", QUrl()); st->isRead = grp.readEntry("isRead", true); st->conversationId = grp.readEntry("conversationId", QString()); st->to = grp.readEntry("to", QStringList()); st->cc = grp.readEntry("cc", QStringList()); st->shares = grp.readEntry("shares", QStringList()); st->replies = grp.readEntry("replies", QUrl()); st->replyToPostId = grp.readEntry("replyToPostId", QString()); st->replyToUser.userName = grp.readEntry("replyToUserName", QString()); st->replyToObjectType = grp.readEntry("replyToObjectType", QString()); list.append(st); } if (!list.isEmpty()) { setLastTimelineId(account, timelineName, list.last()->conversationId); } return list; } QUrl PumpIOMicroBlog::postUrl(Choqok::Account *account, const QString &username, const QString &postId) const { Q_UNUSED(account); return QUrl::fromUserInput(QString(postId).replace(QLatin1String("/api/"), QLatin1Char('/') + username + QLatin1Char('/'))); } QUrl PumpIOMicroBlog::profileUrl(Choqok::Account *account, const QString &username) const { if (username.contains(QLatin1String("acct:"))) { return QUrl::fromUserInput(QStringLiteral("https://%1/%2").arg(hostFromAcct(username)).arg(userNameFromAcct(username))); } else { PumpIOAccount *acc = qobject_cast(account); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(QLatin1Char('/') + username); return url; } } void PumpIOMicroBlog::saveTimeline(Choqok::Account *account, const QString &timelineName, const QList< Choqok::UI::PostWidget * > &timeline) { const QString fileName = Choqok::AccountManager::generatePostBackupFileName(account->alias(), timelineName); KConfig postsBackup(fileName, KConfig::NoGlobals, QStandardPaths::DataLocation); ///Clear previous data: for (const QString &group: postsBackup.groupList()) { postsBackup.deleteGroup(group); } for (Choqok::UI::PostWidget *wd: timeline) { PumpIOPost *post = dynamic_cast(wd->currentPost()); KConfigGroup grp(&postsBackup, post->creationDateTime.toString()); grp.writeEntry("creationDateTime", post->creationDateTime); grp.writeEntry("postId", post->postId); grp.writeEntry("link", post->link); grp.writeEntry("content", post->content); grp.writeEntry("source", post->source); grp.writeEntry("favorited", post->isFavorited); grp.writeEntry("authorId", post->author.userId); grp.writeEntry("authorRealName", post->author.realName); grp.writeEntry("authorUserName", post->author.userName); grp.writeEntry("authorLocation", post->author.location); grp.writeEntry("authorDescription", post->author.description); grp.writeEntry("authorProfileImageUrl", post->author.profileImageUrl); grp.writeEntry("authorHomePageUrl", post->author.homePageUrl); grp.writeEntry("type", post->type); grp.writeEntry("media", post->media); grp.writeEntry("isRead", post->isRead); grp.writeEntry("conversationId", post->conversationId); grp.writeEntry("to", post->to); grp.writeEntry("cc", post->cc); grp.writeEntry("shares", post->shares); grp.writeEntry("replies", post->replies); grp.writeEntry("replyToPostId", post->replyToPostId); grp.writeEntry("replyToUserName", post->replyToUser.userName); grp.writeEntry("replyToObjectType", post->replyToObjectType); } postsBackup.sync(); if (Choqok::Application::isShuttingDown()) { --d->countOfTimelinesToSave; if (d->countOfTimelinesToSave < 1) { Q_EMIT readyForUnload(); } } } Choqok::TimelineInfo *PumpIOMicroBlog::timelineInfo(const QString &timelineName) { return m_timelinesInfos.value(timelineName); } void PumpIOMicroBlog::updateTimelines(Choqok::Account *theAccount) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { for (const QString &timeline: acc->timelineNames()) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + m_timelinesPaths[timeline].arg(acc->username())); QUrlQuery query; const QString lastActivityId(lastTimelineId(theAccount, timeline)); if (!lastActivityId.isEmpty()) { query.addQueryItem(QLatin1String("count"), QString::number(200)); query.addQueryItem(QLatin1String("since"), lastActivityId); } else { query.addQueryItem(QLatin1String("count"), QString::number(Choqok::BehaviorSettings::countOfPosts())); } url.setQuery(query); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; continue; } job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::GetOperation)); m_timelinesRequests[job] = timeline; m_accountJobs[job] = acc; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotUpdateTimeline(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotUpdateTimeline); job->start(); } } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::fetchFollowing(Choqok::Account *theAccount) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/api/user/%1/following").arg(acc->username())); QUrlQuery query; query.addQueryItem(QLatin1String("count"), QString::number(200)); if (!acc->following().isEmpty()) { query.addQueryItem(QLatin1String("since"), acc->following().last()); } url.setQuery(query); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::GetOperation)); m_accountJobs[job] = acc; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFollowing(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotFollowing); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::fetchLists(Choqok::Account *theAccount) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QStringLiteral("/api/user/%1/lists/person").arg(acc->username())); QUrlQuery query; query.addQueryItem(QLatin1String("count"), QString::number(200)); url.setQuery(query); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::GetOperation)); m_accountJobs[job] = acc; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotLists(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotLists); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::share(Choqok::Account *theAccount, Choqok::Post *post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert(QLatin1String("objectType"), post->type); object.insert(QLatin1String("id"), post->postId); QVariantMap item; item.insert(QLatin1String("verb"), QLatin1String("share")); item.insert(QLatin1String("object"), object); const QByteArray data = QJsonDocument::fromVariant(item).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + outboxActivity.arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_shareJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotShare(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotShare); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::toggleFavorite(Choqok::Account *theAccount, Choqok::Post *post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert(QLatin1String("objectType"), post->type); object.insert(QLatin1String("id"), post->postId); QVariantMap item; item.insert(QLatin1String("verb"), post->isFavorited ? QLatin1String("unfavorite") : QLatin1String("favorite")); item.insert(QLatin1String("object"), object); const QByteArray data = QJsonDocument::fromVariant(item).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + outboxActivity.arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_favoriteJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFavorite(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotFavorite); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } void PumpIOMicroBlog::showDirectMessageDialog() { qCDebug(CHOQOK); const QString alias = qobject_cast(sender())->data().toString(); PumpIOAccount *theAccount = qobject_cast(Choqok::AccountManager::self()->findAccount(alias)); PumpIOMessageDialog *msg = new PumpIOMessageDialog(theAccount, Choqok::UI::Global::mainWindow()); msg->show(); } void PumpIOMicroBlog::slotCreatePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_createPostJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); if (!reply[QLatin1String("object")].toMap().value(QLatin1String("id")).toString().isEmpty()) { Choqok::NotifyManager::success(i18n("New post submitted successfully")); ret = 0; Q_EMIT postCreated(theAccount, post); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Creating the new post failed. %1", job->errorString()), MicroBlog::Critical); } } void PumpIOMicroBlog::slotFavorite(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_favoriteJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot set/unset the post as favorite. %1", job->errorString())); } else { post->isFavorited = !post->isFavorited; Q_EMIT favorite(theAccount, post); } } void PumpIOMicroBlog::slotFetchPost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *theAccount = m_accountJobs.take(job); if (!theAccount) { qCDebug(CHOQOK) << "Account or postId is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); PumpIOPost *post = new PumpIOPost; readPost(reply, post); ret = 0; Q_EMIT postFetched(theAccount, post); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot fetch post. %1", job->errorString()), MicroBlog::Critical); } } void PumpIOMicroBlog::slotFetchReplies(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *theAccount = m_accountJobs.take(job); if (!theAccount) { qCDebug(CHOQOK) << "Account or postId is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); const QVariantList items = reply[QLatin1String("items")].toList(); for (int i = items.size() - 1; i >= 0; i--) { QVariantMap item = items.at(i).toMap(); PumpIOPost *r = new PumpIOPost; readPost(item, r); r->replyToPostId = reply[QLatin1String("url")].toString().remove(QLatin1String("/replies")); Q_EMIT postFetched(theAccount, r); } ret = 0; } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot fetch replies. %1", job->errorString()), MicroBlog::Critical); } } void PumpIOMicroBlog::slotFollowing(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *theAccount = m_accountJobs.take(job); if (!theAccount) { qCDebug(CHOQOK) << "Account is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } bool ret = 1; PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { Choqok::UI::Global::mainWindow()->showStatusMessage( i18n("Following list for account %1 has been updated.", acc->username())); KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantList items = json.toVariant().toMap().value(QLatin1String("items")).toList(); QStringList following; for (const QVariant &element: items) { following.append(element.toMap().value(QLatin1String("id")).toString()); } acc->setFollowing(following); ret = 0; Q_EMIT followingFetched(acc); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot retrieve the following list. %1", job->errorString())); } } void PumpIOMicroBlog::slotLists(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *theAccount = m_accountJobs.take(job); if (!theAccount) { qCDebug(CHOQOK) << "Account is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } bool ret = 1; PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { Choqok::UI::Global::mainWindow()->showStatusMessage( i18n("Lists for account %1 has been updated.", acc->username())); KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantList items = json.toVariant().toMap().value(QLatin1String("items")).toList(); QVariantList lists; for (const QVariant &element: items) { QVariantMap e = element.toMap(); QVariantMap list; list.insert(QLatin1String("id"), e.value(QLatin1String("id")).toString()); list.insert(QLatin1String("name"), e.value(QLatin1String("displayName")).toString()); lists.append(list); } acc->setLists(lists); ret = 0; Q_EMIT listsFetched(acc); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot retrieve the lists. %1", job->errorString())); } } void PumpIOMicroBlog::slotShare(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_shareJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { Choqok::UI::Global::mainWindow()->showStatusMessage( i18n("The post has been shared.")); KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap object = json.toVariant().toMap().value(QLatin1String("object")).toMap(); ret = 0; } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Cannot share the post. %1", job->errorString())); } } void PumpIOMicroBlog::slotRemovePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_removePostJobs.take(job); Choqok::Account *theAccount = m_accountJobs.take(job); if (!post || !theAccount) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap object = json.toVariant().toMap().value(QLatin1String("object")).toMap(); if (!object[QLatin1String("deleted")].toString().isEmpty()) { Choqok::NotifyManager::success(i18n("Post removed successfully")); ret = 0; Q_EMIT postRemoved(theAccount, post); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT errorPost(theAccount, post, Choqok::MicroBlog::CommunicationError, i18n("Removing the post failed. %1", job->errorString()), MicroBlog::Critical); } } void PumpIOMicroBlog::slotUpdatePost(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_updateJobs.take(job); Choqok::Account *account = m_accountJobs.take(job); if (!post || !account) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { ret = 0; createPost(account, post); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(account, Choqok::MicroBlog::CommunicationError, i18n("An error occurred when updating the post")); } } void PumpIOMicroBlog::slotUpdateTimeline(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Account *account = m_accountJobs.take(job); if (!account) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(account, Choqok::MicroBlog::CommunicationError, i18n("An error occurred when fetching the timeline")); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QList list = readTimeline(j->data()); const QString timeline(m_timelinesRequests.take(job)); if (!list.isEmpty()) { setLastTimelineId(account, timeline, list.last()->conversationId); } Q_EMIT timelineDataReceived(account, timeline, list); } } void PumpIOMicroBlog::slotUpload(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "Job is null pointer"; return; } Choqok::Post *post = m_uploadJobs.take(job); Choqok::Account *account = m_accountJobs.take(job); if (!post || !account) { qCDebug(CHOQOK) << "Account or Post is NULL pointer"; return; } int ret = 1; if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); const QString id = reply[QLatin1String("id")].toString(); if (!id.isEmpty()) { post->postId = id; post->type = reply[QLatin1String("objectType")].toString(); ret = 0; updatePost(account, post); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } if (ret) { Q_EMIT error(account, Choqok::MicroBlog::CommunicationError, i18n("An error occurred when uploading the media")); } } void PumpIOMicroBlog::fetchReplies(Choqok::Account *theAccount, const QUrl &url) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { if (!url.toDisplayString().startsWith(acc->host())) { qCDebug(CHOQOK) << "You can only fetch replies from your host!"; return; } KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::GetOperation)); m_accountJobs[job] = acc; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchReplies(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotFetchReplies); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } QString PumpIOMicroBlog::lastTimelineId(Choqok::Account *theAccount, const QString &timeline) const { qCDebug(CHOQOK) << "Latest ID for timeline " << timeline << m_timelinesLatestIds[theAccount][timeline]; return m_timelinesLatestIds[theAccount][timeline]; } Choqok::Post *PumpIOMicroBlog::readPost(const QVariantMap &var, Choqok::Post *post) { PumpIOPost *p = dynamic_cast< PumpIOPost * >(post); if (p) { QVariantMap object; if (var.value(QLatin1String("verb")).toString() == QLatin1String("post") || var.value(QLatin1String("verb")).toString() == QLatin1String("share")) { object = var[QLatin1String("object")].toMap(); } else { object = var; } QTextDocument content; if (!object[QLatin1String("displayName")].isNull()) { content.setHtml(object[QLatin1String("displayName")].toString()); p->content = content.toPlainText().trimmed(); p->content += QLatin1Char('\n'); } content.setHtml(object[QLatin1String("content")].toString()); p->content += content.toPlainText().trimmed(); if (!object[QLatin1String("fullImage")].isNull()) { const QVariantMap fullImage = object[QLatin1String("fullImage")].toMap(); if (!fullImage.isEmpty()) { p->media = fullImage[QLatin1String("url")].toUrl(); } } p->creationDateTime = QDateTime::fromString(var[QLatin1String("published")].toString(), Qt::ISODate); p->creationDateTime.setTimeSpec(Qt::UTC); if (object[QLatin1String("pump_io")].isNull()) { p->link = object[QLatin1String("id")].toUrl(); } else { p->link = object[QLatin1String("pump_io")].toMap().value(QLatin1String("proxyURL")).toUrl(); } p->type = object[QLatin1String("objectType")].toString(); p->isFavorited = object[QLatin1String("liked")].toBool(); if (p->isFavorited) { p->isRead = true; } p->postId = object[QLatin1String("id")].toString(); p->conversationId = var[QLatin1String("id")].toString(); QString author; var[QLatin1String("author")].isNull() ? author = QLatin1String("actor") : author = QLatin1String("author"); QVariantMap actor; if (var.value(QLatin1String("verb")).toString() == QLatin1String("share")) { actor = object[QLatin1String("author")].toMap(); const QVariantList shares = object[QLatin1String("shares")].toMap().value(QLatin1String("items")).toList(); for (const QVariant &element: shares) { p->shares.append(element.toMap().value(QLatin1String("id")).toString()); } } else { actor = var[author].toMap(); } const QString userId = actor[QLatin1String("id")].toString(); const QUrl homePageUrl = actor[QLatin1String("url")].toUrl(); p->author.userId = userId; p->author.userName = actor[QLatin1String("preferredUsername")].toString(); p->author.realName = actor[QLatin1String("displayName")].toString(); p->author.homePageUrl = homePageUrl; p->author.location = actor[QLatin1String("location")].toMap().value(QLatin1String("displayName")).toString(); p->author.description = actor[QLatin1String("summary")].toString(); const QUrl profileImageUrl = actor[QLatin1String("image")].toMap().value(QLatin1String("url")).toUrl(); if (!profileImageUrl.isEmpty()) { p->author.profileImageUrl = profileImageUrl; } else if (actor[QLatin1String("objectType")].toString() == QLatin1String("service")) { p->author.profileImageUrl = QUrl::fromUserInput(homePageUrl.toDisplayString() + QLatin1String("images/default.png")); } else { p->author.profileImageUrl = QUrl::fromUserInput(QStringLiteral("https://%1/images/default.png").arg(hostFromAcct(userId))); } if (!var[QLatin1String("generator")].isNull()) { p->source = var[QLatin1String("generator")].toMap().value(QLatin1String("displayName")).toString(); } const QVariantList to = var[QLatin1String("to")].toList(); for (const QVariant &element: to) { QVariantMap toElementMap = element.toMap(); QString toElementType = toElementMap.value(QLatin1String("objectType")).toString(); if (toElementType == QLatin1String("person") || toElementType == QLatin1String("collection")) { const QString toId = toElementMap.value(QLatin1String("id")).toString(); if (toId.compare(QLatin1String("acct:")) != 0) { p->to.append(toId); } } } const QVariantList cc = var[QLatin1String("cc")].toList(); for (const QVariant &element: cc) { QVariantMap ccElementMap = element.toMap(); QString ccElementType = ccElementMap.value(QLatin1String("objectType")).toString(); if (ccElementType == QLatin1String("person") || ccElementType == QLatin1String("collection")) { const QString ccId = ccElementMap.value(QLatin1String("id")).toString(); if (ccId.compare(QLatin1String("acct:")) != 0) { p->cc.append(ccId); } } } const QVariantMap replies = object[QLatin1String("replies")].toMap(); if (replies.value(QLatin1String("pump_io")).isNull()) { p->replies = replies[QLatin1String("url")].toUrl(); } else { p->replies = replies[QLatin1String("pump_io")].toMap().value(QLatin1String("proxyURL")).toUrl(); } return p; } else { qCDebug(CHOQOK) << "post is not a PumpIOPost!"; return post; } } QList< Choqok::Post * > PumpIOMicroBlog::readTimeline(const QByteArray &buffer) { QList posts; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { const QVariantList list = json.toVariant().toMap().value(QLatin1String("items")).toList(); for (const QVariant &element: list) { const QVariantMap elementMap = element.toMap(); if (!elementMap[QLatin1String("object")].toMap().value(QLatin1String("deleted")).isNull()) { // Skip deleted posts continue; } posts.prepend(readPost(elementMap, new PumpIOPost)); } } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } return posts; } void PumpIOMicroBlog::setLastTimelineId(Choqok::Account *theAccount, const QString &timeline, const QString &id) { m_timelinesLatestIds[theAccount][timeline] = id; } void PumpIOMicroBlog::setTimelinesInfo() { Choqok::TimelineInfo *t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Activity"); t->description = i18nc("Timeline description", "You and people you follow"); t->icon = QLatin1String("user-home"); m_timelinesInfos[QLatin1String("Activity")] = t; m_timelinesPaths[QLatin1String("Activity")] = inboxActivity + QLatin1String("/major"); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Favorites"); t->description = i18nc("Timeline description", "Posts you favorited"); t->icon = QLatin1String("favorites"); m_timelinesInfos[QLatin1String("Favorites")] = t; m_timelinesPaths[QLatin1String("Favorites")] = QLatin1String("/api/user/%1/favorites"); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Inbox"); t->description = i18nc("Timeline description", "Posts sent to you"); t->icon = QLatin1String("mail-folder-inbox"); m_timelinesInfos[QLatin1String("Inbox")] = t; m_timelinesPaths[QLatin1String("Inbox")] = inboxActivity + QLatin1String("/direct/major/"); t = new Choqok::TimelineInfo; t->name = i18nc("Timeline Name", "Outbox"); t->description = i18nc("Timeline description", "Posts you sent"); t->icon = QLatin1String("mail-folder-outbox"); m_timelinesInfos[QLatin1String("Outbox")] = t; m_timelinesPaths[QLatin1String("Outbox")] = outboxActivity + QLatin1String("/major/"); } void PumpIOMicroBlog::updatePost(Choqok::Account *theAccount, Choqok::Post *post) { PumpIOAccount *acc = qobject_cast(theAccount); if (acc) { QVariantMap object; object.insert(QLatin1String("id"), post->postId); object.insert(QLatin1String("objectType"), post->type); object.insert(QLatin1String("content"), QUrl::toPercentEncoding(post->content)); // https://github.com/e14n/pump.io/issues/885 QVariantList to; QVariantMap thePublic; thePublic.insert(QLatin1String("objectType"), QLatin1String("collection")); thePublic.insert(QLatin1String("id"), PumpIOMicroBlog::PublicCollection); to.append(thePublic); QVariantMap item; item.insert(QLatin1String("verb"), QLatin1String("update")); item.insert(QLatin1String("object"), object); item.insert(QLatin1String("to"), to); const QByteArray data = QJsonDocument::fromVariant(item).toJson(); QUrl url(acc->host()); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + outboxActivity.arg(acc->username())); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/json")); job->addMetaData(QLatin1String("customHTTPHeader"), acc->oAuth()->authorizationHeader(url, QNetworkAccessManager::PostOperation)); if (!job) { qCDebug(CHOQOK) << "Cannot create an http POST request!"; return; } m_accountJobs[job] = acc; m_updateJobs[job] = post; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotUpdatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &PumpIOMicroBlog::slotUpdatePost); job->start(); } else { qCDebug(CHOQOK) << "theAccount is not a PumpIOAccount!"; } } QString PumpIOMicroBlog::hostFromAcct(const QString &acct) { if (acct.contains(QLatin1String("acct:"))) { return acct.split(QLatin1Char(':'))[1].split(QLatin1Char('@'))[1]; } return acct; } QString PumpIOMicroBlog::userNameFromAcct(const QString &acct) { if (acct.contains(QLatin1String("acct:"))) { return acct.split(QLatin1Char(':'))[1].split(QLatin1Char('@'))[0]; } return acct; } #include "pumpiomicroblog.moc" diff --git a/microblogs/pumpio/pumpiomicroblogwidget.cpp b/microblogs/pumpio/pumpiomicroblogwidget.cpp index 02ad90ef..ad3aa354 100644 --- a/microblogs/pumpio/pumpiomicroblogwidget.cpp +++ b/microblogs/pumpio/pumpiomicroblogwidget.cpp @@ -1,76 +1,76 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2014 Andrea Scarpino Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiomicroblogwidget.h" #include "account.h" #include "timelinewidget.h" #include "pumpiocomposerwidget.h" #include "pumpiodebug.h" PumpIOMicroBlogWidget::PumpIOMicroBlogWidget(Choqok::Account *account, QWidget *parent) : MicroBlogWidget::MicroBlogWidget(account, parent) { } PumpIOMicroBlogWidget::~PumpIOMicroBlogWidget() { } void PumpIOMicroBlogWidget::initUi() { Choqok::UI::MicroBlogWidget::initUi(); } Choqok::UI::TimelineWidget *PumpIOMicroBlogWidget::addTimelineWidgetToUi(const QString &name) { Choqok::UI::TimelineWidget *mbw = currentAccount()->microblog()->createTimelineWidget(currentAccount(), name, this); if (mbw) { Choqok::TimelineInfo *info = currentAccount()->microblog()->timelineInfo(name); timelines().insert(name, mbw); timelinesTabWidget()->addTab(mbw, info->name); timelinesTabWidget()->setTabIcon(timelinesTabWidget()->indexOf(mbw), QIcon::fromTheme(info->icon)); connect(mbw, SIGNAL(updateUnreadCount(int)), this, SLOT(slotUpdateUnreadCount(int))); PumpIOComposerWidget *pumpComposer = qobject_cast(composer()); if (pumpComposer) { connect(mbw, SIGNAL(forwardResendPost(QString)), pumpComposer, SLOT(setText(QString))); - connect(mbw, SIGNAL(forwardReply(QString,QString,QString)), - pumpComposer, SLOT(slotSetReply(QString,QString,QString))); + connect(mbw, &Choqok::UI::TimelineWidget::forwardReply, + pumpComposer, &PumpIOComposerWidget::slotSetReply); } slotUpdateUnreadCount(mbw->unreadCount(), mbw); } else { qCDebug(CHOQOK) << "Cannot Create a new TimelineWidget for timeline " << name; return nullptr; } if (timelinesTabWidget()->count() == 1) { timelinesTabWidget()->setTabBarHidden(true); } else { timelinesTabWidget()->setTabBarHidden(false); } return mbw; } diff --git a/microblogs/pumpio/pumpiopostwidget.cpp b/microblogs/pumpio/pumpiopostwidget.cpp index 38296518..90689746 100644 --- a/microblogs/pumpio/pumpiopostwidget.cpp +++ b/microblogs/pumpio/pumpiopostwidget.cpp @@ -1,278 +1,275 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013-2014 Andrea Scarpino Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpiopostwidget.h" #include #include #include #include #include "mediamanager.h" #include "textbrowser.h" #include "pumpioaccount.h" #include "pumpiodebug.h" #include "pumpiomicroblog.h" #include "pumpiopost.h" #include "pumpioshowthread.h" const QIcon PumpIOPostWidget::unFavIcon(Choqok::MediaManager::convertToGrayScale(QIcon::fromTheme(QLatin1String("rating")).pixmap(16))); class PumpIOPostWidget::Private { public: QPushButton *btnFavorite; QPushButton *btnReply; }; PumpIOPostWidget::PumpIOPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent): PostWidget(account, post, parent), d(new Private) { mainWidget()->document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://thread")), QIcon::fromTheme(QLatin1String("go-top")).pixmap(10)); } PumpIOPostWidget::~PumpIOPostWidget() { delete d; } void PumpIOPostWidget::checkAnchor(const QUrl &url) { if (url.scheme() == QLatin1String("thread")) { PumpIOShowThread *thread = new PumpIOShowThread(currentAccount(), currentPost()); - connect(thread, SIGNAL(forwardReply(QString,QString,QString)), - this, SIGNAL(reply(QString,QString,QString))); + connect(thread, &PumpIOShowThread::forwardReply, this, &PumpIOPostWidget::reply); thread->resize(this->width(), thread->height() * 3); thread->show(); } else { Choqok::UI::PostWidget::checkAnchor(url); } } QString PumpIOPostWidget::generateSign() { QString ss; PumpIOPost *post = dynamic_cast(currentPost()); PumpIOAccount *account = qobject_cast(currentAccount()); PumpIOMicroBlog *microblog = qobject_cast(account->microblog()); if (post) { ss += QStringLiteral("%1 - ").arg(getUsernameHyperlink(currentPost()->author)); QDateTime time; if (currentPost()->repeatedDateTime.isNull()) { time = currentPost()->creationDateTime; } else { time = currentPost()->repeatedDateTime; } ss += QStringLiteral("%3").arg(currentPost()->link.toDisplayString()) .arg(time.toString(Qt::DefaultLocaleLongDate)).arg(formatDateTime(time)); if (!post->source.isEmpty()) { ss += QLatin1String(" - ") + post->source; } const QRegExp followers(QLatin1String("/api/user/\\w+/followers")); if (!post->to.isEmpty()) { ss += QLatin1String(" - "); ss += i18n("To:") + QLatin1Char(' '); for (const QString &id: post->to) { if (id == PumpIOMicroBlog::PublicCollection) { ss += i18n("Public") + QLatin1String(", "); } else if (followers.indexIn(id) != -1) { ss += QLatin1String("") + i18n("Followers") + QLatin1String(", "); } else if (id == QLatin1String("acct:") + account->webfingerID()) { ss += i18n("You") + QLatin1String(", "); } else { ss += QLatin1String("profileUrl(account, post->author.userName).toDisplayString() + QLatin1String("\">") + PumpIOMicroBlog::userNameFromAcct(id) + QLatin1String(", "); } } if (ss.endsWith(QLatin1String(", "))) { ss.chop(2); } } if (!post->cc.isEmpty()) { ss += QLatin1String(" - "); ss += i18n("CC:") + QLatin1Char(' '); for (const QString &id: post->cc) { if (id == PumpIOMicroBlog::PublicCollection) { ss += i18n("Public") + QLatin1String(", "); } else if (followers.indexIn(id) != -1) { ss += QLatin1String("") + i18n("Followers") + QLatin1String(", "); } else if (id == QLatin1String("acct:") + account->webfingerID()) { ss += i18n("You") + QLatin1String(", "); } else { ss += QLatin1String("profileUrl(account, post->author.userName).toDisplayString() + QLatin1String("\">") + PumpIOMicroBlog::userNameFromAcct(id) + QLatin1String(", "); } } if (ss.endsWith(QLatin1String(", "))) { ss.chop(2); } } if (!post->shares.isEmpty()) { ss += QLatin1String(" - "); ss += i18n("Shared by:") + QLatin1Char(' '); for (const QString &id: post->shares) { if (id == QLatin1String("acct:") + account->webfingerID()) { ss += i18n("You") + QLatin1String(", "); } else { ss += QLatin1String("profileUrl(account, post->author.userName).toDisplayString() + QLatin1String("\">") + PumpIOMicroBlog::userNameFromAcct(id) + QLatin1String(", "); } } if (ss.endsWith(QLatin1String(", "))) { ss.chop(2); } } ss += QLatin1String(" "); } else { qCDebug(CHOQOK) << "post is not a PumpIOPost!"; } return ss; } QString PumpIOPostWidget::getUsernameHyperlink(const Choqok::User &user) const { return QStringLiteral("%3") .arg(user.homePageUrl.toDisplayString()) .arg(user.description.isEmpty() ? user.realName : user.description.toHtmlEscaped()) .arg(user.userName); } void PumpIOPostWidget::initUi() { Choqok::UI::PostWidget::initUi(); if (isResendAvailable()) { buttons().value(QLatin1String("btnResend"))->setToolTip(i18nc("@info:tooltip", "Share")); } if (isReplyAvailable()) { d->btnReply = addButton(QLatin1String("btnReply"), i18nc("@info:tooltip", "Reply"), QLatin1String("edit-undo")); QMenu *replyMenu = new QMenu(d->btnReply); QAction *replyToAct = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18n("Reply to %1", currentPost()->author.userName), replyMenu); replyMenu->addAction(replyToAct); - connect(replyToAct, SIGNAL(triggered(bool)), SLOT(slotReplyTo())); - connect(d->btnReply, SIGNAL(clicked(bool)), SLOT(slotReplyTo())); + connect(replyToAct, &QAction::triggered, this, &PumpIOPostWidget::slotReplyTo); + connect(d->btnReply, &QPushButton::clicked, this, &PumpIOPostWidget::slotReplyTo); } d->btnFavorite = addButton(QLatin1String("btnFavorite"), i18nc("@info:tooltip", "Like"), QLatin1String("rating")); d->btnFavorite->setCheckable(true); - connect(d->btnFavorite, SIGNAL(clicked(bool)), this, SLOT(toggleFavorite())); + connect(d->btnFavorite, &QPushButton::clicked, this, &PumpIOPostWidget::toggleFavorite); updateFavStat(); } void PumpIOPostWidget::toggleFavorite() { qCDebug(CHOQOK); setReadWithSignal(); PumpIOMicroBlog *microBlog = qobject_cast(currentAccount()->microblog()); - connect(microBlog, SIGNAL(favorite(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotToggleFavorite(Choqok::Account*,Choqok::Post*))); + connect(microBlog, &PumpIOMicroBlog::favorite, this, &PumpIOPostWidget::slotToggleFavorite); microBlog->toggleFavorite(currentAccount(), currentPost()); } void PumpIOPostWidget::slotToggleFavorite(Choqok::Account *, Choqok::Post *) { qCDebug(CHOQOK); updateFavStat(); } void PumpIOPostWidget::slotPostError(Choqok::Account *theAccount, Choqok::Post *post, Choqok::MicroBlog::ErrorType error, const QString &errorMessage) { Q_UNUSED(error) qCDebug(CHOQOK); if (theAccount == currentAccount() && post == currentPost()) { qCDebug(CHOQOK) << errorMessage; - disconnect(currentAccount()->microblog(), SIGNAL(postRemoved(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotCurrentPostRemoved(Choqok::Account*,Choqok::Post*))); - disconnect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account*,Choqok::Post*,Choqok::MicroBlog::ErrorType,QString,Choqok::MicroBlog::ErrorLevel)), - this, SLOT(slotPostError(Choqok::Account*,Choqok::Post*,Choqok::MicroBlog::ErrorType,QString))); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postRemoved, + this, &PumpIOPostWidget::slotCurrentPostRemoved); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, + this, &PumpIOPostWidget::slotPostError); } } void PumpIOPostWidget::slotResendPost() { qCDebug(CHOQOK); setReadWithSignal(); PumpIOMicroBlog *microBlog = qobject_cast(currentAccount()->microblog()); microBlog->share(currentAccount(), currentPost()); } bool PumpIOPostWidget::isReplyAvailable() { return (currentPost()->type != QLatin1String("comment")); } bool PumpIOPostWidget::isResendAvailable() { return PostWidget::isResendAvailable() && (currentPost()->type != QLatin1String("comment")); } void PumpIOPostWidget::slotReplyTo() { qCDebug(CHOQOK); setReadWithSignal(); PumpIOPost *post = dynamic_cast(currentPost()); if (post->type == QLatin1String("comment")) { Q_EMIT reply(post->replyToPostId, post->replyToUser.userName, post->replyToObjectType); } else { Q_EMIT reply(post->postId, PumpIOMicroBlog::userNameFromAcct(post->author.userId), post->type); } } void PumpIOPostWidget::updateFavStat() { d->btnFavorite->setChecked(currentPost()->isFavorited); if (currentPost()->isFavorited) { d->btnFavorite->setIcon(QIcon::fromTheme(QLatin1String("rating"))); } else { d->btnFavorite->setIcon(unFavIcon); } } diff --git a/microblogs/pumpio/pumpioshowthread.cpp b/microblogs/pumpio/pumpioshowthread.cpp index 121583f1..64783531 100644 --- a/microblogs/pumpio/pumpioshowthread.cpp +++ b/microblogs/pumpio/pumpioshowthread.cpp @@ -1,89 +1,87 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2013-2014 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "pumpioshowthread.h" #include #include "pumpiodebug.h" #include "pumpiomicroblog.h" #include "pumpiopost.h" #include "pumpiopostwidget.h" class PumpIOShowThread::Private { public: Choqok::Account *account; QString postId; }; PumpIOShowThread::PumpIOShowThread(Choqok::Account *account, Choqok::Post *post, QWidget *parent): QWidget(parent) , d(new Private) { d->account = account; d->postId = post->postId; setupUi(this); setWindowTitle(i18nc("Thread of specified user", "Choqok: %1's thread", post->author.userName)); - connect(account->microblog(), SIGNAL(postFetched(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotAddPost(Choqok::Account*,Choqok::Post*))); + connect(account->microblog(), &Choqok::MicroBlog::postFetched, this, + &PumpIOShowThread::slotAddPost); PumpIOPost *p = dynamic_cast(post); if (p) { PumpIOPostWidget *widget = new PumpIOPostWidget(account, p, this); widget->initUi(); widget->setRead(); mainLayout->insertWidget(0, widget); - connect(widget, SIGNAL(reply(QString,QString,QString)), - this, SIGNAL(forwardReply(QString,QString,QString))); + connect(widget, &PumpIOPostWidget::reply, this, &PumpIOShowThread::forwardReply); PumpIOMicroBlog *microblog = qobject_cast(account->microblog()); if (microblog) { microblog->fetchReplies(account, p->replies); } else { qCDebug(CHOQOK) << "Microblog is not a PumpIOMicroBlog"; } } else { qCDebug(CHOQOK) << "Post is not a PumpIOPost"; } } PumpIOShowThread::~PumpIOShowThread() { delete d; } void PumpIOShowThread::slotAddPost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (theAccount == d->account && post->replyToPostId == d->postId) { PumpIOPostWidget *widget = new PumpIOPostWidget(theAccount, post, this); widget->initUi(); widget->setRead(); - connect(widget, SIGNAL(reply(QString,QString,QString)), - this, SIGNAL(forwardReply(QString,QString,QString))); + connect(widget, &PumpIOPostWidget::reply, this, &PumpIOShowThread::forwardReply); mainLayout->insertWidget(mainLayout->count() - 1, widget); } } diff --git a/microblogs/twitter/twittercomposerwidget.cpp b/microblogs/twitter/twittercomposerwidget.cpp index b60ecd29..37b9998b 100644 --- a/microblogs/twitter/twittercomposerwidget.cpp +++ b/microblogs/twitter/twittercomposerwidget.cpp @@ -1,177 +1,173 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twittercomposerwidget.h" #include #include #include #include #include #include #include #include #include "account.h" #include "choqoktextedit.h" #include "notifymanager.h" #include "shortenmanager.h" #include "twitterapiaccount.h" #include "twitterdebug.h" #include "twittermicroblog.h" #include "twittertextedit.h" class TwitterComposerWidget::Private { public: Private() : btnAttach(0), mediumName(0), btnCancel(0) {} QString mediumToAttach; QPushButton *btnAttach; QPointer mediumName; QPointer btnCancel; QGridLayout *editorLayout; }; TwitterComposerWidget::TwitterComposerWidget(Choqok::Account *account, QWidget *parent) : TwitterApiComposerWidget(account, parent), d(new Private) { TwitterTextEdit *edit = new TwitterTextEdit(account, this); QStringListModel *model = new QStringListModel(qobject_cast(account)->friendsList(), this); QCompleter *completer = new QCompleter(model, this); completer->setCaseSensitivity(Qt::CaseInsensitive); edit->setCompleter(completer); setEditor(edit); d->editorLayout = qobject_cast(editorContainer()->layout()); d->btnAttach = new QPushButton(editorContainer()); d->btnAttach->setIcon(QIcon::fromTheme(QLatin1String("mail-attachment"))); d->btnAttach->setToolTip(i18n("Attach a file")); d->btnAttach->setMaximumWidth(d->btnAttach->height()); - connect(d->btnAttach, SIGNAL(clicked(bool)), this, SLOT(selectMediumToAttach())); + connect(d->btnAttach, &QPushButton::clicked, this, &TwitterComposerWidget::selectMediumToAttach); QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addWidget(d->btnAttach); vLayout->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding)); d->editorLayout->addItem(vLayout, 0, 1, 1, 1); } TwitterComposerWidget::~TwitterComposerWidget() { delete d; } void TwitterComposerWidget::submitPost(const QString &txt) { if (d->mediumToAttach.isEmpty()) { Choqok::UI::ComposerWidget::submitPost(txt); } else { qCDebug(CHOQOK); editorContainer()->setEnabled(false); QString text = txt; if (currentAccount()->postCharLimit() && text.size() > (int)currentAccount()->postCharLimit()) { text = Choqok::ShortenManager::self()->parseText(text); } setPostToSubmit(nullptr); setPostToSubmit(new Choqok::Post); postToSubmit()->content = text; if (!replyToId.isEmpty()) { postToSubmit()->replyToPostId = replyToId; } - connect(currentAccount()->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - SLOT(slotPostMediaSubmitted(Choqok::Account*,Choqok::Post*))); - connect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, this, + &TwitterComposerWidget::slotPostMediaSubmitted); + connect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, this, + &TwitterComposerWidget::slotErrorPost); btnAbort = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18n("Abort"), this); layout()->addWidget(btnAbort); - connect(btnAbort, SIGNAL(clicked(bool)), SLOT(abort())); + connect(btnAbort, &QPushButton::clicked, this, &TwitterComposerWidget::abort); TwitterMicroBlog *mBlog = qobject_cast(currentAccount()->microblog()); mBlog->createPostWithAttachment(currentAccount(), postToSubmit(), d->mediumToAttach); } } void TwitterComposerWidget::slotPostMediaSubmitted(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (currentAccount() == theAccount && post == postToSubmit()) { qCDebug(CHOQOK) << "Accepted"; - disconnect(currentAccount()->microblog(), SIGNAL(postCreated(Choqok::Account*,Choqok::Post*)), - this, SLOT(slotPostMediaSubmitted(Choqok::Account*,Choqok::Post*))); - disconnect(currentAccount()->microblog(), - SIGNAL(errorPost(Choqok::Account *, Choqok::Post *, Choqok::MicroBlog::ErrorType, - QString, Choqok::MicroBlog::ErrorLevel)), - this, SLOT(slotErrorPost(Choqok::Account*,Choqok::Post*))); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::postCreated, + this, &TwitterComposerWidget::slotPostMediaSubmitted); + disconnect(currentAccount()->microblog(), &Choqok::MicroBlog::errorPost, + this, &TwitterComposerWidget::slotErrorPost); if (btnAbort) { btnAbort->deleteLater(); } Choqok::NotifyManager::success(i18n("New post submitted successfully")); editor()->clear(); replyToId.clear(); editorContainer()->setEnabled(true); setPostToSubmit(nullptr); cancelAttachMedium(); currentAccount()->microblog()->updateTimelines(currentAccount()); } } void TwitterComposerWidget::selectMediumToAttach() { qCDebug(CHOQOK); d->mediumToAttach = QFileDialog::getOpenFileName(this, i18n("Select Media to Upload"), QString(), QStringLiteral("Images")); if (d->mediumToAttach.isEmpty()) { return; } QString fileName = QUrl(d->mediumToAttach).fileName(); if (!d->mediumName) { qCDebug(CHOQOK) << fileName; d->mediumName = new QLabel(editorContainer()); d->btnCancel = new QPushButton(editorContainer()); d->btnCancel->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->btnCancel->setToolTip(i18n("Discard Attachment")); d->btnCancel->setMaximumWidth(d->btnCancel->height()); - connect(d->btnCancel, SIGNAL(clicked(bool)), SLOT(cancelAttachMedium())); + connect(d->btnCancel, &QPushButton::clicked, this, &TwitterComposerWidget::cancelAttachMedium); d->editorLayout->addWidget(d->mediumName, 1, 0); d->editorLayout->addWidget(d->btnCancel, 1, 1); } d->mediumName->setText(i18n("Attaching %1", fileName)); editor()->setFocus(); } void TwitterComposerWidget::cancelAttachMedium() { qCDebug(CHOQOK); delete d->mediumName; d->mediumName = 0; delete d->btnCancel; d->btnCancel = 0; d->mediumToAttach.clear(); } diff --git a/microblogs/twitter/twitterdmessagedialog.cpp b/microblogs/twitter/twitterdmessagedialog.cpp index 6e536499..a836a1f0 100644 --- a/microblogs/twitter/twitterdmessagedialog.cpp +++ b/microblogs/twitter/twitterdmessagedialog.cpp @@ -1,78 +1,78 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2015 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterdmessagedialog.h" #include #include #include "choqoktextedit.h" #include "twitterapiaccount.h" #include "twitterapidebug.h" #include "twitterapimicroblog.h" TwitterDMessageDialog::TwitterDMessageDialog(TwitterApiAccount *theAccount, QWidget *parent, Qt::WindowFlags flags) : TwitterApiDMessageDialog(theAccount, parent, flags) { fetchTextLimit(); } TwitterDMessageDialog::~TwitterDMessageDialog() { } void TwitterDMessageDialog::fetchTextLimit() { QUrl url = account()->apiUrl(); url.setPath(url.path() + QLatin1String("/help/configuration.json")); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } TwitterApiMicroBlog *mBlog = qobject_cast(account()->microblog()); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(mBlog->authorizationHeader(account(), url, QNetworkAccessManager::GetOperation))); - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotTextLimit(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterDMessageDialog::slotTextLimit); job->start(); } void TwitterDMessageDialog::slotTextLimit(KJob *job) { if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const int textLimit = json.toVariant().toMap().value(QLatin1String("dm_text_character_limit")).toInt(); editor()->setCharLimit(textLimit); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } } diff --git a/microblogs/twitter/twittereditaccount.cpp b/microblogs/twitter/twittereditaccount.cpp index 6852857b..95aa073a 100644 --- a/microblogs/twitter/twittereditaccount.cpp +++ b/microblogs/twitter/twittereditaccount.cpp @@ -1,159 +1,160 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twittereditaccount.h" #include #include +#include #include #include #include "accountmanager.h" #include "choqoktools.h" #include "twitteraccount.h" #include "twitterdebug.h" #include "twittermicroblog.h" #include "twitterapioauth.h" TwitterEditAccountWidget::TwitterEditAccountWidget(TwitterMicroBlog *microblog, TwitterAccount *account, QWidget *parent) : ChoqokEditAccountWidget(account, parent), mAccount(account) { setupUi(this); kcfg_basicAuth->hide(); - connect(kcfg_authorize, SIGNAL(clicked(bool)), SLOT(authorizeUser())); + connect(kcfg_authorize, &QPushButton::clicked, this, &TwitterEditAccountWidget::authorizeUser); if (mAccount) { kcfg_alias->setText(mAccount->alias()); setAuthenticated(!mAccount->oauthToken().isEmpty() && !mAccount->oauthTokenSecret().isEmpty()); } else { setAuthenticated(false); QString newAccountAlias = microblog->serviceName(); QString servName = newAccountAlias; int counter = 1; while (Choqok::AccountManager::self()->findAccount(newAccountAlias)) { newAccountAlias = QStringLiteral("%1%2").arg(servName).arg(counter); counter++; } setAccount(mAccount = new TwitterAccount(microblog, newAccountAlias)); kcfg_alias->setText(newAccountAlias); } loadTimelinesTableState(); kcfg_alias->setFocus(Qt::OtherFocusReason); } TwitterEditAccountWidget::~TwitterEditAccountWidget() { } bool TwitterEditAccountWidget::validateData() { if (kcfg_alias->text().isEmpty() || !isAuthenticated) { return false; } else { return true; } } Choqok::Account *TwitterEditAccountWidget::apply() { qCDebug(CHOQOK); mAccount->setAlias(kcfg_alias->text()); mAccount->setOauthToken(mAccount->oauthInterface()->token().toLatin1()); mAccount->setOauthTokenSecret(mAccount->oauthInterface()->tokenSecret().toLatin1()); saveTimelinesTableState(); mAccount->writeConfig(); return mAccount; } void TwitterEditAccountWidget::authorizeUser() { qCDebug(CHOQOK); mAccount->oauthInterface()->grant(); connect(mAccount->oauthInterface(), &QAbstractOAuth::authorizeWithBrowser, &Choqok::openUrl); connect(mAccount->oauthInterface(), &QAbstractOAuth::statusChanged, this, &TwitterEditAccountWidget::getPinCode); } void TwitterEditAccountWidget::getPinCode() { isAuthenticated = false; if (mAccount->oauthInterface()->status() == QAbstractOAuth::Status::TemporaryCredentialsReceived) { QString verifier = QInputDialog::getText(this, i18n("PIN"), i18n("Enter the PIN received from Twitter:")); if (verifier.isEmpty()) { return; } mAccount->oauthInterface()->continueGrantWithVerifier(verifier); } else if (mAccount->oauthInterface()->status() == QAbstractOAuth::Status::Granted) { setAuthenticated(true); KMessageBox::information(this, i18n("Choqok is authorized successfully."), i18n("Authorized")); } else { KMessageBox::detailedError(this, i18n("Authorization Error"), i18n("OAuth authorization error")); } } void TwitterEditAccountWidget::setAuthenticated(bool authenticated) { isAuthenticated = authenticated; if (authenticated) { kcfg_authorize->setIcon(QIcon::fromTheme(QLatin1String("object-unlocked"))); kcfg_authenticateLed->on(); kcfg_authenticateStatus->setText(i18n("Authenticated")); } else { kcfg_authorize->setIcon(QIcon::fromTheme(QLatin1String("object-locked"))); kcfg_authenticateLed->off(); kcfg_authenticateStatus->setText(i18n("Not Authenticated")); } } void TwitterEditAccountWidget::loadTimelinesTableState() { for (const QString &timeline: mAccount->microblog()->timelineNames()) { int newRow = timelinesTable->rowCount(); timelinesTable->insertRow(newRow); timelinesTable->setItem(newRow, 0, new QTableWidgetItem(timeline)); QCheckBox *enable = new QCheckBox(timelinesTable); enable->setChecked(mAccount->timelineNames().contains(timeline)); timelinesTable->setCellWidget(newRow, 1, enable); } } void TwitterEditAccountWidget::saveTimelinesTableState() { QStringList timelines; int rowCount = timelinesTable->rowCount(); for (int i = 0; i < rowCount; ++i) { QCheckBox *enable = qobject_cast(timelinesTable->cellWidget(i, 1)); if (enable && enable->isChecked()) { timelines << timelinesTable->item(i, 0)->text(); } } timelines.removeDuplicates(); mAccount->setTimelineNames(timelines); } diff --git a/microblogs/twitter/twitterlistdialog.cpp b/microblogs/twitter/twitterlistdialog.cpp index 7371a77e..14d59dd0 100644 --- a/microblogs/twitter/twitterlistdialog.cpp +++ b/microblogs/twitter/twitterlistdialog.cpp @@ -1,146 +1,146 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterlistdialog.h" #include +#include #include +#include #include #include #include "twitteraccount.h" #include "twitterdebug.h" #include "twittermicroblog.h" TwitterListDialog::TwitterListDialog(TwitterApiAccount *theAccount, QWidget *parent) : QDialog(parent) { if (theAccount) { account = qobject_cast(theAccount); if (!account) { qCCritical(CHOQOK) << "TwitterListDialog: ERROR, the provided account is not a valid Twitter account"; return; } } else { qCCritical(CHOQOK) << "TwitterListDialog: ERROR, theAccount is NULL"; return; } blog = qobject_cast(account->microblog()); mainWidget = new QWidget(this); ui.setupUi(mainWidget); - connect(ui.username, SIGNAL(textChanged(QString)), SLOT(slotUsernameChanged(QString))); - connect(ui.loadUserLists, SIGNAL(clicked(bool)), SLOT(loadUserLists())); + connect(ui.username, &QLineEdit::textChanged, this, &TwitterListDialog::slotUsernameChanged); + connect(ui.loadUserLists, &QPushButton::clicked, this, &TwitterListDialog::loadUserLists); QRegExp rx(QLatin1String("([a-z0-9_]){1,20}(\\/)"), Qt::CaseInsensitive); QValidator *val = new QRegExpValidator(rx, 0); ui.username->setValidator(val); ui.username->setFocus(); listWidget = new QListWidget(this); QGridLayout *layout = new QGridLayout; layout->addWidget(ui.label, 0, 0); layout->addWidget(ui.username, 0, 1); layout->addWidget(ui.loadUserLists, 0, 2); layout->addWidget(listWidget, 1, 0, 1, -1); layout->addWidget(ui.label_2, 2, 0); layout->addWidget(ui.listname, 2, 1, 1, -1); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); okButton->setText(i18n("Add")); QPushButton *cancelButton = buttonBox->button(QDialogButtonBox::Cancel); cancelButton->setIcon(KStandardGuiItem::close().icon()); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &TwitterListDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &TwitterListDialog::reject); layout->addWidget(buttonBox, 3, 3, 1, -1); mainWidget->setLayout(layout); mainWidget->adjustSize(); } TwitterListDialog::~TwitterListDialog() { } void TwitterListDialog::accept() { if (ui.listname->text().isEmpty() || ui.username->text().isEmpty()) { KMessageBox::error(this, i18n("You should provide both list author username and list name.")); } else { blog->addListTimeline(account, ui.username->text(), ui.listname->text()); QDialog::accept(); } } void TwitterListDialog::slotUsernameChanged(const QString &name) { if (name.endsWith(QLatin1Char('/'))) { QString n = name; n.chop(1); ui.username->setText(n); ui.listname->setFocus(); } listWidget->clear(); ui.listname->clear(); } void TwitterListDialog::loadUserLists() { if (ui.username->text().isEmpty()) { KMessageBox::error(choqokMainWindow, i18n("No user.")); return; } - connect(blog, SIGNAL(userLists(Choqok::Account*,QString,QList)), - SLOT(slotLoadUserlists(Choqok::Account*,QString,QList))); + connect(blog, &TwitterMicroBlog::userLists, this, &TwitterListDialog::slotLoadUserlists); blog->fetchUserLists(account, ui.username->text()); } void TwitterListDialog::slotLoadUserlists(Choqok::Account *theAccount, QString username, QList list) { if (theAccount == account && QString::compare(username, ui.username->text()) == 0 && !list.isEmpty()) { listWidget->clear(); for (const Twitter::List &l: list) { QListWidgetItem *item = new QListWidgetItem(listWidget); QString iText; if (l.description.isEmpty()) { iText = l.fullname; } else { iText = QStringLiteral("%1 [%2]").arg(l.fullname).arg(l.description); } item->setText(iText); item->setData(32, l.slug); listWidget->addItem(item); } - connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)), - SLOT(slotListItemChanged(QListWidgetItem*))); + connect(listWidget, &QListWidget::itemClicked, this, &TwitterListDialog::slotListItemChanged); } } void TwitterListDialog::slotListItemChanged(QListWidgetItem *item) { ui.listname->setText(item->data(32).toString()); } diff --git a/microblogs/twitter/twittermicroblog.cpp b/microblogs/twitter/twittermicroblog.cpp index f20a7451..2296fd64 100644 --- a/microblogs/twitter/twittermicroblog.cpp +++ b/microblogs/twitter/twittermicroblog.cpp @@ -1,576 +1,575 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twittermicroblog.h" #include #include #include #include #include #include #include #include #include "account.h" #include "accountmanager.h" #include "choqokappearancesettings.h" #include "choqokbehaviorsettings.h" #include "choqoktypes.h" #include "composerwidget.h" #include "editaccountwidget.h" #include "mediamanager.h" #include "postwidget.h" #include "timelinewidget.h" #include "twitterapimicroblogwidget.h" #include "twitteraccount.h" #include "twittercomposerwidget.h" #include "twitterdebug.h" #include "twitterdmessagedialog.h" #include "twittereditaccount.h" #include "twitterlistdialog.h" #include "twitterpostwidget.h" #include "twittersearch.h" #include "twittertimelinewidget.h" K_PLUGIN_FACTORY_WITH_JSON(TwitterMicroBlogFactory, "choqok_twitter.json", registerPlugin < TwitterMicroBlog > ();) TwitterMicroBlog::TwitterMicroBlog(QObject *parent, const QVariantList &) : TwitterApiMicroBlog(QLatin1String("choqok_twitter"), parent) { qCDebug(CHOQOK); setServiceName(QLatin1String("Twitter")); setServiceHomepageUrl(QLatin1String("https://twitter.com/")); timelineApiPath[QLatin1String("Reply")] = QLatin1String("/statuses/mentions_timeline.json"); setTimelineInfos(); } void TwitterMicroBlog::setTimelineInfos() { // hange description of replies to mentions Choqok::TimelineInfo *t = mTimelineInfos[QLatin1String("Reply")]; t->name = i18nc("Timeline Name", "Mentions"); t->description = i18nc("Timeline description", "Mentions of you"); } TwitterMicroBlog::~TwitterMicroBlog() { qCDebug(CHOQOK); } Choqok::Account *TwitterMicroBlog::createNewAccount(const QString &alias) { TwitterAccount *acc = qobject_cast(Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return new TwitterAccount(this, alias); } else { return 0; } } ChoqokEditAccountWidget *TwitterMicroBlog::createEditAccountWidget(Choqok::Account *account, QWidget *parent) { qCDebug(CHOQOK); TwitterAccount *acc = qobject_cast(account); if (acc || !account) { return new TwitterEditAccountWidget(this, acc, parent); } else { qCDebug(CHOQOK) << "Account passed here is not a TwitterAccount!"; return nullptr; } } Choqok::UI::MicroBlogWidget *TwitterMicroBlog::createMicroBlogWidget(Choqok::Account *account, QWidget *parent) { return new TwitterApiMicroBlogWidget(account, parent); } Choqok::UI::TimelineWidget *TwitterMicroBlog::createTimelineWidget(Choqok::Account *account, const QString &timelineName, QWidget *parent) { return new TwitterTimelineWidget(account, timelineName, parent); } Choqok::UI::PostWidget *TwitterMicroBlog::createPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent) { return new TwitterPostWidget(account, post, parent); } Choqok::UI::ComposerWidget *TwitterMicroBlog::createComposerWidget(Choqok::Account *account, QWidget *parent) { return new TwitterComposerWidget(account, parent); } QUrl TwitterMicroBlog::profileUrl(Choqok::Account *account, const QString &username) const { Q_UNUSED(account) return QUrl::fromUserInput(QStringLiteral("https://twitter.com/%1").arg(username)); } QUrl TwitterMicroBlog::postUrl(Choqok::Account *, const QString &username, const QString &postId) const { return QUrl::fromUserInput(QStringLiteral("https://twitter.com/%1/status/%2").arg(username).arg(postId)); } TwitterApiSearch *TwitterMicroBlog::searchBackend() { if (!mSearchBackend) { mSearchBackend = new TwitterSearch(this); } return mSearchBackend; } void TwitterMicroBlog::createPostWithAttachment(Choqok::Account *theAccount, Choqok::Post *post, const QString &mediumToAttach) { if (mediumToAttach.isEmpty()) { TwitterApiMicroBlog::createPost(theAccount, post); } else { const QUrl picUrl = QUrl::fromUserInput(mediumToAttach); KIO::StoredTransferJob *picJob = KIO::storedGet(picUrl, KIO::Reload, KIO::HideProgressInfo); picJob->exec(); if (picJob->error()) { qCCritical(CHOQOK) << "Job error:" << picJob->errorString(); KMessageBox::detailedError(Choqok::UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file."), picJob->errorString()); return; } const QByteArray picData = picJob->data(); if (picData.count() == 0) { qCCritical(CHOQOK) << "Cannot read the media file, please check if it exists."; KMessageBox::error(Choqok::UI::Global::mainWindow(), i18n("Uploading medium failed: cannot read the medium file.")); return; } TwitterAccount *account = qobject_cast(theAccount); QUrl url = account->uploadUrl(); url.setPath(url.path() + QLatin1String("/statuses/update_with_media.json")); const QMimeDatabase db; QByteArray fileContentType = db.mimeTypeForUrl(picUrl).name().toUtf8(); QMap formdata; formdata[QLatin1String("status")] = post->content.toUtf8(); if (!post->replyToPostId.isEmpty()) { formdata[QLatin1String("in_reply_to_status_id")] = post->replyToPostId.toLatin1(); } formdata[QLatin1String("source")] = QCoreApplication::applicationName().toLatin1(); QMap mediafile; mediafile[QLatin1String("name")] = "media[]"; mediafile[QLatin1String("filename")] = picUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = fileContentType; mediafile[QLatin1String("medium")] = picData; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "Cannot create a http POST request!"; return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: multipart/form-data; boundary=AaB03x")); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::PostOperation))); mCreatePostMap[ job ] = post; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotCreatePost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterMicroBlog::slotCreatePost); job->start(); } } void TwitterMicroBlog::verifyCredentials(TwitterAccount *theAccount) { qCDebug(CHOQOK); QUrl url = theAccount->apiUrl(); url.setPath(url.path() + QStringLiteral("/account/verify_credentials.json")); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(theAccount, url, QNetworkAccessManager::GetOperation))); mJobsAccount[ job ] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchVerifyCredentials(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterMicroBlog::slotFetchVerifyCredentials); job->start(); } void TwitterMicroBlog::slotFetchVerifyCredentials(KJob *job) { if (!job) { qCWarning(CHOQOK) << "NULL Job returned"; return; } TwitterAccount *theAccount = qobject_cast(mJobsAccount.take(job)); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Verify credentials failed. %1", job->errorString()), Low); } else { KIO::StoredTransferJob *stj = qobject_cast (job); const QJsonDocument json = QJsonDocument::fromJson(stj->data()); if (!json.isNull()) { theAccount->setUsername(json.object()[QLatin1String("screen_name")].toString()); theAccount->setUserId(json.object()[QLatin1String("id_str")].toString()); } } } void TwitterMicroBlog::showDirectMessageDialog(TwitterApiAccount *theAccount, const QString &toUsername) { qCDebug(CHOQOK); if (!theAccount) { QAction *act = qobject_cast(sender()); theAccount = qobject_cast( Choqok::AccountManager::self()->findAccount(act->data().toString())); } TwitterDMessageDialog *dmsg = new TwitterDMessageDialog(theAccount, Choqok::UI::Global::mainWindow()); if (!toUsername.isEmpty()) { dmsg->setTo(toUsername); } dmsg->show(); } QString TwitterMicroBlog::generateRepeatedByUserTooltip(const QString &username) { if (Choqok::AppearanceSettings::showRetweetsInChoqokWay()) { return i18n("Retweet of %1", username); } else { return i18n("Retweeted by %1", username); } } QString TwitterMicroBlog::repeatQuestion() { return i18n("Retweet to your followers?"); } QMenu *TwitterMicroBlog::createActionsMenu(Choqok::Account *theAccount, QWidget *parent) { QMenu *menu = TwitterApiMicroBlog::createActionsMenu(theAccount, parent); QAction *lists = new QAction(i18n("Add User List..."), menu); lists->setData(theAccount->alias()); connect(lists, SIGNAL(triggered(bool)), SLOT(showListDialog())); menu->addAction(lists); return menu; } void TwitterMicroBlog::showListDialog(TwitterApiAccount *theAccount) { if (!theAccount) { QAction *act = qobject_cast(sender()); theAccount = qobject_cast( Choqok::AccountManager::self()->findAccount(act->data().toString())); } QPointer listDlg = new TwitterListDialog(theAccount, Choqok::UI::Global::mainWindow()); listDlg->show(); } void TwitterMicroBlog::fetchUserLists(TwitterAccount *theAccount, const QString &username) { qCDebug(CHOQOK); if (!theAccount) { return; } QUrl url = theAccount->apiUrl(); url.setPath(url.path() + QLatin1String("/lists/ownerships.json")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("screen_name"), username); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCCritical(CHOQOK) << "TwitterMicroBlog::loadUserLists: Cannot create an http GET request!"; return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(theAccount, url, QNetworkAccessManager::GetOperation))); mFetchUsersListMap[ job ] = username; mJobsAccount[ job ] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchUserLists(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterMicroBlog::slotFetchUserLists); job->start(); } void TwitterMicroBlog::slotFetchUserLists(KJob *job) { qCDebug(CHOQOK); if (!job) { qCWarning(CHOQOK) << "NULL Job returned"; return; } QString username = mFetchUsersListMap.take(job); Choqok::Account *theAccount = mJobsAccount.take(job); if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); Q_EMIT error(theAccount, Choqok::MicroBlog::CommunicationError, i18n("Fetching %1's lists failed. %2", username, job->errorString()), Critical); } else { KIO::StoredTransferJob *stj = qobject_cast (job); QByteArray buffer = stj->data(); QList list = readUserListsFromJson(theAccount, buffer); if (list.isEmpty()) { qCDebug(CHOQOK) << buffer; QString errorMsg; errorMsg = checkForError(buffer); if (errorMsg.isEmpty()) { KMessageBox::information(choqokMainWindow, i18n("There is no list record for user %1", username)); } else { Q_EMIT error(theAccount, ServerError, errorMsg, Critical); } } else { Q_EMIT userLists(theAccount, username, list); } } } Choqok::Post *TwitterMicroBlog::readDirectMessage(Choqok::Account *theAccount, const QVariantMap &var) { qCDebug(CHOQOK); Choqok::Post *post = TwitterApiMicroBlog::readDirectMessage(theAccount, var); if (!post) { qCCritical(CHOQOK) << "post is NULL!"; return 0; } post->postId = var[QLatin1String("id_str")].toString(); return post; } void TwitterMicroBlog::addListTimeline(TwitterAccount *theAccount, const QString &username, const QString &listname) { qCDebug(CHOQOK); QStringList tms = theAccount->timelineNames(); QString name = QStringLiteral("@%1/%2").arg(username).arg(listname); tms.append(name); addTimelineName(name); theAccount->setTimelineNames(tms); theAccount->writeConfig(); timelineApiPath[name] = QLatin1String("/lists/statuses.json"); updateTimelines(theAccount); } // TODO: Change to new API void TwitterMicroBlog::setListTimelines(TwitterAccount *theAccount, const QStringList &lists) { qCDebug(CHOQOK) << lists; QStringList tms = theAccount->timelineNames(); for (const QString &name: lists) { tms.append(name); addTimelineName(name); timelineApiPath[name] = QLatin1String("/lists/statuses.json"); } tms.removeDuplicates(); theAccount->setTimelineNames(tms); } Choqok::TimelineInfo *TwitterMicroBlog::timelineInfo(const QString &timelineName) { if (timelineName.startsWith(QLatin1Char('@'))) { if (mListsInfo.contains(timelineName)) { return mListsInfo.value(timelineName); } else { Choqok::TimelineInfo *info = new Choqok::TimelineInfo; info->description = info->name = timelineName; info->icon = QLatin1String("format-list-unordered"); mListsInfo.insert(timelineName, info); return info; } } else { return TwitterApiMicroBlog::timelineInfo(timelineName); } } QList< Twitter::List > TwitterMicroBlog::readUserListsFromJson(Choqok::Account *theAccount, QByteArray buffer) { QList twitterList; const QJsonDocument json = QJsonDocument::fromJson(buffer); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); if (map.contains(QLatin1String("lists"))) { for (const QVariant &list: map[QLatin1String("lists")].toList()) { twitterList.append(readListFromJsonMap(theAccount, list.toMap())); } } } return twitterList; } Twitter::List TwitterMicroBlog::readListFromJsonMap(Choqok::Account *theAccount, QVariantMap map) { Twitter::List l; l.author = readUser(theAccount, map[QLatin1String("user")].toMap()); l.description = map[QLatin1String("description")].toString(); l.fullname = map[QLatin1String("full_name")].toString(); l.isFollowing = map[QLatin1String("following")].toBool(); l.listId = map[QLatin1String("id")].toString(); l.memberCount = map[QLatin1String("member_count")].toInt(); l.mode = (map[QLatin1String("mode")].toString() == QLatin1String("public") ? Twitter::Public : Twitter::Private); l.name = map[QLatin1String("name")].toString(); l.slug = map[QLatin1String("slug")].toString(); l.subscriberCount = map[QLatin1String("subscriber_count")].toInt(); l.uri = map[QLatin1String("uri")].toString(); return l; } Choqok::Post *TwitterMicroBlog::readPost(Choqok::Account *account, const QVariantMap &var, Choqok::Post *post) { if (!post) { qCCritical(CHOQOK) << "TwitterMicroBlog::readPost: post is NULL!"; return 0; } post = TwitterApiMicroBlog::readPost(account, var, post); post->postId = var[QLatin1String("id_str")].toString(); post->replyToPostId = var[QLatin1String("in_reply_to_status_id_str")].toString(); post->replyToUser.userId = var[QLatin1String("in_reply_to_user_id_str")].toString(); // Support for extended tweet_mode if (var.contains(QLatin1String("full_text"))) { post->content = var[QLatin1String("full_text")].toString(); } //postId is changed, regenerate link url post->link = postUrl(account, post->author.userName, post->postId); QVariantMap userMap = var[QLatin1String("user")].toMap(); post->author.userId = userMap[QLatin1String("id_str")].toString(); return post; } void TwitterMicroBlog::fetchPost(Choqok::Account *theAccount, Choqok::Post *post) { qCDebug(CHOQOK); if (!post || post->postId.isEmpty()) { return; } TwitterAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + QStringLiteral("/statuses/show/%1.json").arg(post->postId)); QUrl tmpUrl(url); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("tweet_mode"), QLatin1String("extended")); url.setQuery(urlQuery); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; // QString errMsg = i18n ( "Fetching the new post failed. Cannot create an HTTP GET request." // "Please check your KDE installation." ); // emit errorPost ( theAccount, post, Choqok::MicroBlog::OtherError, errMsg, Low ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, tmpUrl, QNetworkAccessManager::GetOperation))); mFetchPostMap[ job ] = post; mJobsAccount[ job ] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotFetchPost(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterMicroBlog::slotFetchPost); job->start(); } void TwitterMicroBlog::requestTimeLine(Choqok::Account *theAccount, QString type, QString latestStatusId, int page, QString maxId) { qCDebug(CHOQOK); TwitterAccount *account = qobject_cast(theAccount); QUrl url = account->apiUrl(); url.setPath(url.path() + timelineApiPath[type]); QUrlQuery urlQuery; // needed because lists have different parameter names but // returned timelines have the same JSON format if (timelineApiPath[type].contains(QLatin1String("lists/statuses"))) { // type contains @username/timelinename const QString slug = type.mid(type.indexOf(QLatin1String("/")) + 1); urlQuery.addQueryItem(QLatin1String("slug"), slug); const QString owner = type.mid(1, type.indexOf(QLatin1String("/")) - 1); urlQuery.addQueryItem(QLatin1String("owner_screen_name"), owner); } else { int countOfPost = Choqok::BehaviorSettings::countOfPosts(); if (!latestStatusId.isEmpty()) { urlQuery.addQueryItem(QLatin1String("since_id"), latestStatusId); countOfPost = 200; } urlQuery.addQueryItem(QLatin1String("count"), QString::number(countOfPost)); if (!maxId.isEmpty()) { urlQuery.addQueryItem(QLatin1String("max_id"), maxId); } if (page) { urlQuery.addQueryItem(QLatin1String("page"), QString::number(page)); } } urlQuery.addQueryItem(QLatin1String("tweet_mode"), QLatin1String("extended")); url.setQuery(urlQuery); qCDebug(CHOQOK) << "Latest" << type << "Id:" << latestStatusId;// << "apiReq:" << url; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo) ; if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; // QString errMsg = i18n ( "Cannot create an http GET request. Please check your KDE installation." ); // emit error ( theAccount, OtherError, errMsg, Low ); return; } job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mRequestTimelineMap[job] = type; mJobsAccount[job] = theAccount; - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotRequestTimeline(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterMicroBlog::slotRequestTimeline); job->start(); } #include "twittermicroblog.moc" diff --git a/microblogs/twitter/twitterpostwidget.cpp b/microblogs/twitter/twitterpostwidget.cpp index 3fd47d7d..d9fb409f 100644 --- a/microblogs/twitter/twitterpostwidget.cpp +++ b/microblogs/twitter/twitterpostwidget.cpp @@ -1,300 +1,300 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitterpostwidget.h" #include #include #include #include #include "choqokbehaviorsettings.h" #include "choqoktools.h" #include "mediamanager.h" #include "textbrowser.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" #include "twitterapiwhoiswidget.h" #include "twittersearch.h" const QRegExp TwitterPostWidget::mTwitterUserRegExp(QLatin1String("([\\s\\W]|^)@([a-z0-9_]+){1,20}"), Qt::CaseInsensitive); const QRegExp TwitterPostWidget::mTwitterTagRegExp(QLatin1String("([\\s]|^)#([\\w_\\.\\-]+)"), Qt::CaseInsensitive); const QString TwitterPostWidget::mQuotedTextBase(QLatin1String("")); const QUrl TwitterPostWidget::mQuotedAvatarResourceUrl(QLatin1String("img://quotedProfileImage")); TwitterPostWidget::TwitterPostWidget(Choqok::Account *account, Choqok::Post *post, QWidget *parent): TwitterApiPostWidget(account, post, parent) { } TwitterPostWidget::~TwitterPostWidget() { } void TwitterPostWidget::initUi() { TwitterApiPostWidget::initUi(); if ( ! currentPost()->quotedPost.content.isEmpty() ) { if( !setupQuotedAvatar() ){ _mainWidget->document()->addResource(QTextDocument::ImageResource, mQuotedAvatarResourceUrl, Choqok::MediaManager::self()->defaultImage()); } auto dir = getDirection(currentPost()->quotedPost.content); auto text = prepareStatus(currentPost()->quotedPost.content); QString user = QStringLiteral("%1").arg(currentPost()->quotedPost.user.userName); QString quoteText = mQuotedTextBase.arg(text, dir, user, QLatin1String("background-color:%1;")); setExtraContents(quoteText.arg(getBackgroundColor())); updateUi(); } QPushButton *btn = buttons().value(QLatin1String("btnResend")); if (btn) { QMenu *menu = new QMenu(btn); QAction *resend = new QAction(i18n("Manual ReSend"), menu); - connect(resend, SIGNAL(triggered(bool)), SLOT(slotResendPost())); + connect(resend, &QAction::triggered, this, &TwitterPostWidget::slotResendPost); QAction *repeat = new QAction(i18n("Retweet"), menu); repeat->setToolTip(i18n("Retweet post using API")); - connect(repeat, SIGNAL(triggered(bool)), SLOT(repeatPost())); + connect(repeat, &QAction::triggered, this, &TwitterPostWidget::repeatPost); // If person protects their acc, we will use simple adding RT before message if (!currentPost()->author.isProtected) { menu->addAction(repeat); } menu->addAction(resend); btn->setMenu(menu); } } QString TwitterPostWidget::prepareStatus(const QString &text) { QString res = TwitterApiPostWidget::prepareStatus(text); res.replace(mTwitterUserRegExp, QLatin1String("\\1@\\2")); res.replace(mTwitterTagRegExp, QLatin1String("\\1#\\2")); return res; } bool TwitterPostWidget::isRemoveAvailable() { if (currentAccount()->username().compare(currentPost()->author.userName, Qt::CaseInsensitive) == 0) { return true; } else if (currentPost()->isPrivate) { return true; } else { return false; } } void TwitterPostWidget::slotReplyToAll() { QStringList nicks; nicks.append(currentPost()->author.userName); QString txt = QStringLiteral("@%1 ").arg(currentPost()->author.userName); int pos = 0; while ((pos = mTwitterUserRegExp.indexIn(currentPost()->content, pos)) != -1) { if (mTwitterUserRegExp.cap(2).toLower() != currentAccount()->username() && mTwitterUserRegExp.cap(2).toLower() != currentPost()->author.userName && !nicks.contains(mTwitterUserRegExp.cap(2).toLower())) { nicks.append(mTwitterUserRegExp.cap(2)); txt += QStringLiteral("@%1 ").arg(mTwitterUserRegExp.cap(2)); } pos += mTwitterUserRegExp.matchedLength(); } txt.chop(1); Q_EMIT reply(txt, currentPost()->postId, currentPost()->author.userName); } void TwitterPostWidget::checkAnchor(const QUrl &url) { QString scheme = url.scheme(); TwitterApiMicroBlog *blog = qobject_cast(currentAccount()->microblog()); TwitterApiAccount *account = qobject_cast(currentAccount()); if (scheme == QLatin1String("tag")) { blog->searchBackend()->requestSearchResults(currentAccount(), QUrl::fromAce(url.host().toUtf8()), (int)TwitterSearch::ReferenceHashtag); } else if (scheme == QLatin1String("user")) { QMenu menu; QAction *info = new QAction(QIcon::fromTheme(QLatin1String("user-identity")), i18nc("Who is user", "Who is %1", url.host()), &menu); QAction *from = new QAction(QIcon::fromTheme(QLatin1String("edit-find-user")), i18nc("Posts from user", "Posts from %1", url.host()), &menu); QAction *to = new QAction(QIcon::fromTheme(QLatin1String("meeting-attending")), i18nc("Replies to user", "Replies to %1", url.host()), &menu); QAction *cont = new QAction(QIcon::fromTheme(QLatin1String("user-properties")), i18nc("Including user name", "Including %1", url.host()), &menu); QAction *openInBrowser = new QAction(QIcon::fromTheme(QLatin1String("applications-internet")), i18nc("Open profile page in browser", "Open profile in browser"), &menu); from->setData(TwitterSearch::FromUser); to->setData(TwitterSearch::ToUser); cont->setData(TwitterSearch::ReferenceUser); menu.addAction(info); menu.addAction(from); menu.addAction(to); menu.addAction(cont); menu.addAction(openInBrowser); //Subscribe/UnSubscribe/Block bool isSubscribe = false; QString accountUsername = currentAccount()->username().toLower(); QString postUsername = url.host().toLower(); QAction *subscribe = 0, *block = 0, *replyTo = 0, *dMessage = 0, *reportSpam = 0; if (accountUsername != postUsername) { menu.addSeparator(); QMenu *actionsMenu = menu.addMenu(QIcon::fromTheme(QLatin1String("applications-system")), i18n("Actions")); replyTo = new QAction(QIcon::fromTheme(QLatin1String("edit-undo")), i18nc("Write a message to user attention", "Write to %1", url.host()), actionsMenu); actionsMenu->addAction(replyTo); if (account->friendsList().contains(url.host(), Qt::CaseInsensitive)) { dMessage = new QAction(QIcon::fromTheme(QLatin1String("mail-message-new")), i18nc("Send direct message to user", "Send private message to %1", url.host()), actionsMenu); actionsMenu->addAction(dMessage); isSubscribe = false;//It's UnSubscribe subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-remove-user")), i18nc("Unfollow user", "Unfollow %1", url.host()), actionsMenu); } else { isSubscribe = true; subscribe = new QAction(QIcon::fromTheme(QLatin1String("list-add-user")), i18nc("Follow user", "Follow %1", url.host()), actionsMenu); } block = new QAction(QIcon::fromTheme(QLatin1String("dialog-cancel")), i18nc("Block user", "Block %1", url.host()), actionsMenu); reportSpam = new QAction(QIcon::fromTheme(QLatin1String("irc-voice")), i18nc("Report user", "Report %1 as spam", url.host()), actionsMenu); actionsMenu->addAction(subscribe); actionsMenu->addAction(block); actionsMenu->addAction(reportSpam); } QAction *ret = menu.exec(QCursor::pos()); if (ret == 0) { return; } if (ret == info) { TwitterApiWhoisWidget *wd = new TwitterApiWhoisWidget(account, url.host(), *currentPost(), this); wd->show(QCursor::pos()); return; } else if (ret == subscribe) { if (isSubscribe) { blog->createFriendship(currentAccount(), url.host()); } else { blog->destroyFriendship(currentAccount(), url.host()); } return; } else if (ret == block) { blog->blockUser(currentAccount(), url.host()); return; } else if (ret == reportSpam) { blog->reportUserAsSpam(currentAccount(), url.host()); return; } else if (ret == openInBrowser) { Choqok::openUrl(currentAccount()->microblog()->profileUrl(currentAccount(), url.host())); return; } else if (ret == replyTo) { Q_EMIT reply(QStringLiteral("@%1").arg(url.host()), QString(), url.host()); return; } else if (ret == dMessage) { blog->showDirectMessageDialog(account, url.host()); return; } int type = ret->data().toInt(); blog->searchBackend()->requestSearchResults(currentAccount(), url.host(), type, QString(), Choqok::BehaviorSettings::countOfPosts()); } else { TwitterApiPostWidget::checkAnchor(url); } } bool TwitterPostWidget::setupQuotedAvatar() { QPixmap pix = Choqok::MediaManager::self()->fetchImage(currentPost()->quotedPost.user.profileImageUrl, Choqok::MediaManager::Async); if (!pix.isNull()) { quotedAvatarFetched(currentPost()->quotedPost.user.profileImageUrl, pix); return true; } else { - connect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(quotedAvatarFetched(QUrl,QPixmap))); - connect(Choqok::MediaManager::self(), SIGNAL(fetchError(QString,QString)), - this, SLOT(quotedAvatarFetchError(QString,QString))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &TwitterPostWidget::quotedAvatarFetched); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::fetchError, + this, &TwitterPostWidget::quotedAvatarFetchError); return false; } } void TwitterPostWidget::quotedAvatarFetched(const QUrl &remoteUrl, const QPixmap &pixmap) { if (remoteUrl == currentPost()->quotedPost.user.profileImageUrl) { _mainWidget->document()->addResource(QTextDocument::ImageResource, mQuotedAvatarResourceUrl, pixmap); - disconnect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - this, SLOT(quotedAvatarFetched(QUrl,QPixmap))); - disconnect(Choqok::MediaManager::self(), SIGNAL(fetchError(QString,QString)), - this, SLOT(quotedAvatarFetchError(QString,QString))); + disconnect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &TwitterPostWidget::quotedAvatarFetched); + disconnect(Choqok::MediaManager::self(), &Choqok::MediaManager::fetchError, + this, &TwitterPostWidget::quotedAvatarFetchError); } } void TwitterPostWidget::quotedAvatarFetchError(const QUrl &remoteUrl, const QString &errMsg) { Q_UNUSED(errMsg); if (remoteUrl == currentPost()->quotedPost.user.profileImageUrl) { ///Avatar fetching is failed! but will not disconnect to get the img if it fetches later! _mainWidget->document()->addResource(QTextDocument::ImageResource, mQuotedAvatarResourceUrl, QIcon::fromTheme(QLatin1String("image-missing")).pixmap(40)); } } QString TwitterPostWidget::getBackgroundColor() { QString style = styleSheet(); QLatin1String str{ "background-color:rgb(" }; int idx = style.indexOf(str); if(idx != -1){ idx += str.size(); int endIdx = style.indexOf(QLatin1String(");"), idx); if( endIdx != -1 ){ QStringList rgb = style.mid(idx, endIdx-idx).split(QLatin1Char(',')); if( rgb.size() == 3 ){ return QStringLiteral("#%1%2%3").arg( rgb[0].toInt() - 20, 2, 16, QLatin1Char('0') ) .arg( rgb[1].toInt() - 20, 2, 16, QLatin1Char('0') ) .arg( rgb[2].toInt() - 20, 2, 16, QLatin1Char('0') ); } } } return QLatin1String("#ffffff"); } diff --git a/microblogs/twitter/twittersearch.cpp b/microblogs/twitter/twittersearch.cpp index c82e199a..52e89882 100644 --- a/microblogs/twitter/twittersearch.cpp +++ b/microblogs/twitter/twittersearch.cpp @@ -1,200 +1,200 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twittersearch.h" #include #include #include #include "twitterapimicroblog.h" #include "twitteraccount.h" #include "twitterdebug.h" const QRegExp TwitterSearch::m_rId(QLatin1String("tag:search.twitter.com,[0-9]+:([0-9]+)")); TwitterSearch::TwitterSearch(QObject *parent): TwitterApiSearch(parent) { qCDebug(CHOQOK); mSearchCode[CustomSearch].clear(); mSearchCode[ToUser] = QLatin1String("to:"); mSearchCode[FromUser] = QLatin1String("from:"); mSearchCode[ReferenceUser] = QLatin1Char('@'); mSearchCode[ReferenceHashtag] = QLatin1Char('#'); mI18nSearchCode[CustomSearch].clear(); mI18nSearchCode[ReferenceUser] = QLatin1Char('@'); mI18nSearchCode[ReferenceHashtag] = QLatin1Char('#'); mI18nSearchCode[ToUser] = i18nc("Posts sent to user", "To:"); mI18nSearchCode[FromUser] = i18nc("Posts from user, Sent by user", "From:"); mSearchTypes[CustomSearch].first = i18n("Custom Search"); mSearchTypes[CustomSearch].second = true; mSearchTypes[ToUser].first = i18nc("Tweets are Twitter posts", "Tweets To This User"); mSearchTypes[ToUser].second = true; mSearchTypes[FromUser].first = i18nc("Tweets are Twitter posts", "Tweets From This User"); mSearchTypes[FromUser].second = true; mSearchTypes[ReferenceUser].first = i18nc("Tweets are Twitter posts", "Tweets Including This Username"); mSearchTypes[ReferenceUser].second = true; mSearchTypes[ReferenceHashtag].first = i18nc("Tweets are Twitter posts", "Tweets Including This Hashtag"); mSearchTypes[ReferenceHashtag].second = true; } void TwitterSearch::requestSearchResults(const SearchInfo &searchInfo, const QString &sinceStatusId, uint count, uint page) { Q_UNUSED(page) qCDebug(CHOQOK); TwitterAccount *account = qobject_cast< TwitterAccount * >(searchInfo.account); QUrl url = account->apiUrl(); QUrlQuery urlQuery; const QString query = searchInfo.query; if (searchInfo.option == TwitterSearch::FromUser) { url.setPath(url.path() + QLatin1String("/statuses/user_timeline.json")); urlQuery.addQueryItem(QLatin1String("screen_name"), query); } else { url.setPath(url.path() + QLatin1String("/search/tweets.json")); const QByteArray formattedQuery(QUrl::toPercentEncoding(mSearchCode[searchInfo.option] + query)); urlQuery.addQueryItem(QLatin1String("q"), QString::fromLatin1(formattedQuery)); } if (!sinceStatusId.isEmpty()) { urlQuery.addQueryItem(QLatin1String("since_id"), sinceStatusId); } int cntStr; if (count && count <= 100) { // Twitter API specifies a max count of 100 cntStr = count; } else { cntStr = 100; } urlQuery.addQueryItem(QLatin1String("tweet_mode"), QLatin1String("extended")); urlQuery.addQueryItem(QLatin1String("count"), QString::number(cntStr)); url.setQuery(urlQuery); qCDebug(CHOQOK) << url; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCCritical(CHOQOK) << "Cannot create an http GET request!"; return; } TwitterApiMicroBlog *microblog = qobject_cast(account->microblog()); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(microblog->authorizationHeader(account, url, QNetworkAccessManager::GetOperation))); mSearchJobs[job] = searchInfo; - connect(job, SIGNAL(result(KJob*)), this, SLOT(searchResultsReturned(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterSearch::searchResultsReturned); job->start(); } void TwitterSearch::searchResultsReturned(KJob *job) { qCDebug(CHOQOK); if (!job) { qCDebug(CHOQOK) << "job is a null pointer"; Q_EMIT error(i18n("Unable to fetch search results.")); return; } const SearchInfo info = mSearchJobs.take(job); QList postsList; if (job->error()) { qCCritical(CHOQOK) << "Error:" << job->errorString(); Q_EMIT error(i18n("Unable to fetch search results: %1", job->errorString())); } else { KIO::StoredTransferJob *jj = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(jj->data()); if (!json.isNull()) { if (info.option == TwitterSearch::FromUser) { for (const QVariant elem: json.toVariant().toList()) { postsList.prepend(readStatusesFromJsonMap(elem.toMap())); } } else { const QVariantMap map = json.toVariant().toMap(); if (map.contains(QLatin1String("statuses"))) { for (const QVariant elem: map[QLatin1String("statuses")].toList()) { postsList.prepend(readStatusesFromJsonMap(elem.toMap())); } } } } } Q_EMIT searchResultsReceived(info, postsList); } Choqok::Post *TwitterSearch::readStatusesFromJsonMap(const QVariantMap &var) { Choqok::Post *post = new Choqok::Post; post->content = var[QLatin1String("text")].toString(); // Support for extended tweet_mode if (var.contains(QLatin1String("full_text"))) { post->content = var[QLatin1String("full_text")].toString(); } //%*s %s %d %d:%d:%d %d %d post->creationDateTime = dateFromString(var[QLatin1String("created_at")].toString()); post->postId = var[QLatin1String("id")].toString(); post->source = var[QLatin1String("source")].toString(); QVariantMap userMap = var[QLatin1String("user")].toMap(); post->author.realName = userMap[QLatin1String("name")].toString(); post->author.userName = userMap[QLatin1String("screen_name")].toString(); post->author.profileImageUrl = userMap[QLatin1String("profile_image_url")].toUrl(); post->isPrivate = false; post->isFavorited = false; post->replyToPostId = var[QLatin1String("in_reply_to_status_id_str")].toString(); post->replyToUser.userName = var[QLatin1String("in_reply_to_screen_name")].toString(); post->link = QUrl::fromUserInput(QStringLiteral("https://twitter.com/%1/status/%2").arg(post->author.userName).arg(post->postId)); return post; } QString TwitterSearch::optionCode(int option) { return mI18nSearchCode[option]; } TwitterSearch::~TwitterSearch() { } diff --git a/microblogs/twitter/twittertextedit.cpp b/microblogs/twitter/twittertextedit.cpp index e83bc61f..31662621 100644 --- a/microblogs/twitter/twittertextedit.cpp +++ b/microblogs/twitter/twittertextedit.cpp @@ -1,149 +1,149 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2017 Andrea Scarpino This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twittertextedit.h" #include #include #include #include "urlutils.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" #include "twitterdebug.h" class TwitterTextEdit::Private { public: Private(Choqok::Account *theAccount) : acc(theAccount), tCoMaximumLength(0), tCoMaximumLengthHttps(0) {} Choqok::Account *acc; int tCoMaximumLength; int tCoMaximumLengthHttps; }; TwitterTextEdit::TwitterTextEdit(Choqok::Account *theAccount, QWidget *parent) : TwitterApiTextEdit(theAccount, parent), d(new Private(theAccount)) { qCDebug(CHOQOK); fetchTCoMaximumLength(); } TwitterTextEdit::~TwitterTextEdit() { delete d; } void TwitterTextEdit::updateRemainingCharsCount() { QString txt = this->toPlainText(); int count = txt.count(); if (count) { lblRemainChar->show(); if (charLimit()) { int remain = charLimit() - count; for (const QString &url: UrlUtils::detectUrls(txt)) { // Twitter does not wrapps urls with login informations if (!url.contains(QLatin1Char('@'))) { int diff = -1; if (url.startsWith(QLatin1String("http://"))) { diff = url.length() - d->tCoMaximumLength; } else if (url.startsWith(QLatin1String("https://"))) { diff = url.length() - d->tCoMaximumLengthHttps; } if (diff > 0) { remain += diff; } } } if (remain < 0) { lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: red;}")); } else if (remain < 30) { lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: rgb(242, 179, 19);}")); } else { lblRemainChar->setStyleSheet(QLatin1String("QLabel {color: green;}")); } lblRemainChar->setText(QString::number(remain)); } else { lblRemainChar->setText(QString::number(count)); lblRemainChar->setStyleSheet(QLatin1String(QLatin1String("QLabel {color: blue;}"))); } txt.remove(QRegExp(QLatin1String("@([^\\s\\W]+)"))); txt = txt.trimmed(); if (firstChar() != txt[0]) { setFirstChar(txt[0]); txt.prepend(QLatin1Char(' ')); QTextBlockFormat f; f.setLayoutDirection((Qt::LayoutDirection) txt.isRightToLeft()); textCursor().mergeBlockFormat(f); } } else { lblRemainChar->hide(); } } void TwitterTextEdit::fetchTCoMaximumLength() { TwitterApiAccount *acc = qobject_cast(d->acc); if (acc) { QUrl url = acc->apiUrl(); url.setPath(url.path() + QLatin1String("/help/configuration.json")); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); if (!job) { qCDebug(CHOQOK) << "Cannot create an http GET request!"; return; } TwitterApiMicroBlog *mBlog = qobject_cast(acc->microblog()); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: ") + QLatin1String(mBlog->authorizationHeader(acc, url, QNetworkAccessManager::GetOperation))); - connect(job, SIGNAL(result(KJob*)), this, SLOT(slotTCoMaximumLength(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &TwitterTextEdit::slotTCoMaximumLength); job->start(); } else { qCDebug(CHOQOK) << "the account is not a TwitterAPIAccount!"; } } void TwitterTextEdit::slotTCoMaximumLength(KJob *job) { if (job->error()) { qCDebug(CHOQOK) << "Job Error:" << job->errorString(); } else { KIO::StoredTransferJob *j = qobject_cast(job); const QJsonDocument json = QJsonDocument::fromJson(j->data()); if (!json.isNull()) { const QVariantMap reply = json.toVariant().toMap(); d->tCoMaximumLength = reply[QLatin1String("short_url_length")].toInt(); d->tCoMaximumLengthHttps = reply[QLatin1String("short_url_length_https")].toInt(); } else { qCDebug(CHOQOK) << "Cannot parse JSON reply"; } } } diff --git a/plugins/betternotify/dummynotification.cpp b/plugins/betternotify/dummynotification.cpp index 3fdce29c..5ccabfcf 100644 --- a/plugins/betternotify/dummynotification.cpp +++ b/plugins/betternotify/dummynotification.cpp @@ -1,93 +1,93 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "dummynotification.h" #include #include #include #include "choqokappearancesettings.h" #include "choqoktools.h" #include "notifysettings.h" #include "postwidget.h" DummyNotification::DummyNotification(const QFont &font, const QColor &color, const QColor &background, QWidget *parent) : QTextBrowser(parent), isMoving(false) { setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); setWindowOpacity(0.8); setWindowFlags(Qt::ToolTip); setFrameShape(QFrame::NoFrame); setOpenExternalLinks(false); setOpenLinks(false); setTextInteractionFlags(Qt::LinksAccessibleByMouse); document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("img://profileImage")), QIcon::fromTheme(QLatin1String("choqok")).pixmap(48)); document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://close")), QIcon::fromTheme(QLatin1String("dialog-ok")).pixmap(16)); setText(baseText.arg(i18n("Choqok")).arg(i18n("KDE Rocks! :)")).arg(i18n("OK"))); - connect(this, SIGNAL(anchorClicked(QUrl)), SLOT(slotProcessAnchor(QUrl))); + connect(this, &DummyNotification::anchorClicked, this, &DummyNotification::slotProcessAnchor); QString fntStr = QLatin1String("font-family:\"") + font.family() + QLatin1String("\"; font-size:") + QString::number(font.pointSize()) + QLatin1String("pt;"); fntStr += (font.bold() ? QLatin1String(" font-weight:bold;") : QString()) + (font.italic() ? QLatin1String(" font-style:italic;") : QString()); QString style = Choqok::UI::PostWidget::getBaseStyle().arg(Choqok::getColorString(color), Choqok::getColorString(background), fntStr); setStyleSheet(style); } DummyNotification::~DummyNotification() { } void DummyNotification::mouseMoveEvent(QMouseEvent *ev) { QTextBrowser::mouseMoveEvent(ev); if (isMoving) { QPoint diff = ev->globalPos() - lastPressedPosition; lastPressedPosition = ev->globalPos(); QPoint newPos = pos() + diff; move(newPos); } } void DummyNotification::mousePressEvent(QMouseEvent *ev) { QTextBrowser::mousePressEvent(ev); isMoving = true; lastPressedPosition = ev->globalPos(); } void DummyNotification::mouseReleaseEvent(QMouseEvent *ev) { QTextBrowser::mouseReleaseEvent(ev); isMoving = false; } void DummyNotification::slotProcessAnchor(const QUrl &url) { if (url.scheme() == QLatin1String("choqok")) { if (url.host() == QLatin1String("close")) { Q_EMIT positionSelected(pos()); } } } diff --git a/plugins/betternotify/notification.cpp b/plugins/betternotify/notification.cpp index e2eae4c0..9807237d 100644 --- a/plugins/betternotify/notification.cpp +++ b/plugins/betternotify/notification.cpp @@ -1,145 +1,145 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2011-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "notification.h" #include #include #include #include #include "choqokappearancesettings.h" #include "choqoktools.h" #include "mediamanager.h" #include "notifysettings.h" const QRegExp Notification::dirRegExp(QLatin1String("(RT|RD)|(@([^\\s\\W]+))|(#([^\\s\\W]+))|(!([^\\s\\W]+))")); Notification::Notification(Choqok::UI::PostWidget *postWidget) : QWidget(), post(postWidget), dir(QLatin1String("ltr")) { setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); // setAttribute(Qt::WA_TranslucentBackground); setWindowOpacity(0.8); setWindowFlags(Qt::ToolTip); setDirection(); mainWidget.viewport()->setAutoFillBackground(false); mainWidget.setFrameShape(QFrame::NoFrame); mainWidget.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); mainWidget.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); mainWidget.setOpenExternalLinks(false); mainWidget.setOpenLinks(false); setMouseTracking(true); resize(NOTIFICATION_WIDTH, NOTIFICATION_HEIGHT); NotifySettings set(this); QFont fnt = set.font(); QColor color = set.foregroundColor(); QColor back = set.backgroundColor(); QString fntStr = QLatin1String("font-family:\"") + fnt.family() + QLatin1String("\"; font-size:") + QString::number(fnt.pointSize()) + QLatin1String("pt;"); fntStr += (fnt.bold() ? QLatin1String(" font-weight:bold;") : QString()) + (fnt.italic() ? QLatin1String(" font-style:italic;") : QString()); QString style = Choqok::UI::PostWidget::getBaseStyle().arg(Choqok::getColorString(color), Choqok::getColorString(back), fntStr); setStyleSheet(style); init(); - connect(&mainWidget, SIGNAL(anchorClicked(QUrl)), SLOT(slotProcessAnchor(QUrl))); + connect(&mainWidget, &MyTextBrowser::anchorClicked, this, &Notification::slotProcessAnchor); } Notification::~Notification() { } QSize Notification::sizeHint() const { return QSize(NOTIFICATION_WIDTH, NOTIFICATION_HEIGHT); } void Notification::init() { QPixmap pix = Choqok::MediaManager::self()->fetchImage(post->currentPost()->author.profileImageUrl); if (!pix) { pix = QPixmap(Choqok::MediaManager::self()->defaultImage()); } mainWidget.document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("img://profileImage")), pix); mainWidget.document()->addResource(QTextDocument::ImageResource, QUrl(QLatin1String("icon://close")), QIcon::fromTheme(QLatin1String("dialog-close")).pixmap(16)); mainWidget.setText(baseText.arg(post->currentPost()->author.userName) .arg(post->currentPost()->content) .arg(dir) .arg(i18n("Ignore"))); QVBoxLayout *l = new QVBoxLayout(this); l->setContentsMargins(0, 0, 0, 0); l->setSpacing(0); l->addWidget(&mainWidget); setHeight(); - connect(&mainWidget, SIGNAL(clicked()), SLOT(slotClicked())); - connect(&mainWidget, SIGNAL(mouseEntered()), SIGNAL(mouseEntered())); - connect(&mainWidget, SIGNAL(mouseLeaved()), SIGNAL(mouseLeaved())); + connect(&mainWidget, &MyTextBrowser::clicked, this, &Notification::slotClicked); + connect(&mainWidget, &MyTextBrowser::mouseEntered, this, &Notification::mouseEntered); + connect(&mainWidget, &MyTextBrowser::mouseLeaved, this, &Notification::mouseLeaved); //TODO Show remaining post count to notify } void Notification::slotProcessAnchor(const QUrl &url) { if (url.scheme() == QLatin1String("choqok")) { if (url.host() == QLatin1String("close")) { Q_EMIT ignored(); } } } void Notification::slotClicked() { post->setReadWithSignal(); Q_EMIT postReaded(); } void Notification::setHeight() { mainWidget.document()->setTextWidth(mainWidget.width() - 2); int h = mainWidget.document()->size().toSize().height() + 30; setMinimumHeight(h); setMaximumHeight(h); } void Notification::setDirection() { QString txt = post->currentPost()->content; txt.remove(dirRegExp); txt = txt.trimmed(); if (txt.isRightToLeft()) { dir = QLatin1String("rtl"); } } void Notification::mouseMoveEvent(QMouseEvent *e) { e->accept(); } diff --git a/plugins/betternotify/notify.cpp b/plugins/betternotify/notify.cpp index 89ad4a35..dae9100d 100644 --- a/plugins/betternotify/notify.cpp +++ b/plugins/betternotify/notify.cpp @@ -1,130 +1,128 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2011-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "notify.h" #include #include #include "account.h" #include "application.h" #include "choqokuiglobal.h" #include "mediamanager.h" #include "postwidget.h" #include "notification.h" #include "notifysettings.h" K_PLUGIN_FACTORY_WITH_JSON(NotifyFactory, "choqok_notify.json", registerPlugin < Notify > ();) Notify::Notify(QObject *parent, const QList< QVariant > &) : Choqok::Plugin(QLatin1String("choqok_betternotify"), parent), notification(0) { NotifySettings set; accountsList = set.accounts(); timer.setInterval(set.notifyInterval() * 1000); - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - this, - SLOT(slotNewPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString))); - connect(&timer, SIGNAL(timeout()), this, SLOT(notifyNextPost())); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &Notify::slotNewPostWidgetAdded); + connect(&timer, &QTimer::timeout, this, &Notify::notifyNextPost); notifyPosition = set.position(); } Notify::~Notify() { } void Notify::slotNewPostWidgetAdded(Choqok::UI::PostWidget *pw, Choqok::Account *acc, QString tm) { // qDebug()<isRead() && accountsList[acc->alias()].contains(tm)) { //qDebug()<<"POST ADDED TO NOTIFY IT: "<currentPost()->content; postQueueToNotify.enqueue(pw); if (!timer.isActive()) { notifyNextPost(); timer.start(); } } } void Notify::notifyNextPost() { if (postQueueToNotify.isEmpty()) { timer.stop(); if (notification) { hideLastNotificationAndShowThis(); } } else { notify(postQueueToNotify.dequeue()); } } void Notify::notify(QPointer< Choqok::UI::PostWidget > post) { if (post) { Notification *notif = new Notification(post); - connect(notif, SIGNAL(ignored()), this, SLOT(stopNotifications())); - connect(notif, SIGNAL(postReaded()), SLOT(slotPostReaded())); - connect(notif, SIGNAL(mouseEntered()), &timer, SLOT(stop())); - connect(notif, SIGNAL(mouseLeaved()), &timer, SLOT(start())); + connect(notif, &Notification::ignored, this, &Notify::stopNotifications); + connect(notif, &Notification::postReaded, this, &Notify::slotPostReaded); + connect(notif, &Notification::mouseEntered, &timer, &QTimer::stop); + connect(notif, &Notification::mouseLeaved, &timer, (void (QTimer::*)())&QTimer::start); hideLastNotificationAndShowThis(notif); } else { hideLastNotificationAndShowThis(); } } void Notify::slotPostReaded() { notifyNextPost(); timer.stop(); timer.start(); } void Notify::stopNotifications() { postQueueToNotify.clear(); timer.stop(); hideLastNotificationAndShowThis(); } void Notify::hideLastNotificationAndShowThis(Notification *nextNotificationToShow) { //TODO: Add Animation notification->deleteLater(); notification = 0; if (nextNotificationToShow) { notification = nextNotificationToShow; notification->move(notifyPosition); notification->show(); } } #include "notify.moc" diff --git a/plugins/betternotify/notifyconfig.cpp b/plugins/betternotify/notifyconfig.cpp index c8b357de..5426757a 100644 --- a/plugins/betternotify/notifyconfig.cpp +++ b/plugins/betternotify/notifyconfig.cpp @@ -1,143 +1,151 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2011-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "notifyconfig.h" +#include +#include +#include + #include +#include +#include #include #include "account.h" #include "accountmanager.h" #include "dummynotification.h" #include "notifysettings.h" K_PLUGIN_FACTORY_WITH_JSON(NotifyConfigFactory, "choqok_notify_config.json", registerPlugin < NotifyConfig > ();) NotifyConfig::NotifyConfig(QWidget *parent, const QVariantList &args) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_notify")), parent, args) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mNotifyCtl")); ui.setupUi(wd); layout->addWidget(wd); - connect(ui.accountsList, SIGNAL(currentRowChanged(int)), SLOT(updateTimelinesList())); - connect(ui.timelinesList, SIGNAL(itemSelectionChanged()), SLOT(timelineSelectionChanged())); - connect(ui.interval, SIGNAL(valueChanged(int)), this, SLOT(emitChanged())); - connect(ui.adjustPosition, SIGNAL(clicked()), this, SLOT(slotAdjustNotificationPosition())); - connect(ui.backgroundColor, SIGNAL(changed(QColor)), this, SLOT(emitChanged())); - connect(ui.foregroundColor, SIGNAL(changed(QColor)), this, SLOT(emitChanged())); - connect(ui.font, SIGNAL(fontSelected(QFont)), this, SLOT(emitChanged())); + connect(ui.accountsList, &QListWidget::currentRowChanged, + this, &NotifyConfig::updateTimelinesList); + connect(ui.timelinesList, &QListWidget::itemSelectionChanged, + this, &NotifyConfig::timelineSelectionChanged); + connect(ui.interval, (void (QSpinBox::*)(int))&QSpinBox::valueChanged, this, &NotifyConfig::emitChanged); + connect(ui.adjustPosition, &QPushButton::clicked, this, &NotifyConfig::slotAdjustNotificationPosition); + connect(ui.backgroundColor, &KColorButton::changed, this, &NotifyConfig::emitChanged); + connect(ui.foregroundColor, &KColorButton::changed, this, &NotifyConfig::emitChanged); + connect(ui.font, &KFontRequester::fontSelected, this, &NotifyConfig::emitChanged); settings = new NotifySettings(this); ui.lblArrow->setPixmap(QIcon::fromTheme(QLatin1String("arrow-right")).pixmap(48)); } NotifyConfig::~NotifyConfig() { } void NotifyConfig::emitChanged() { Q_EMIT changed(true); } void NotifyConfig::updateTimelinesList() { ui.timelinesList->blockSignals(true); ui.timelinesList->clear(); QString acc = ui.accountsList->currentItem()->text(); Choqok::Account *account = Choqok::AccountManager::self()->findAccount(acc); for (const QString &tm: account->timelineNames()) { ui.timelinesList->addItem(tm); if (accounts[acc].contains(tm)) { ui.timelinesList->item(ui.timelinesList->count() - 1)->setSelected(true); } } ui.timelinesList->blockSignals(false); } void NotifyConfig::timelineSelectionChanged() { QStringList lst; for (QListWidgetItem *item: ui.timelinesList->selectedItems()) { lst.append(item->text()); } accounts[ui.accountsList->currentItem()->text()] = lst; Q_EMIT changed(); } void NotifyConfig::load() { accounts = settings->accounts(); ui.interval->setValue(settings->notifyInterval()); for (const QString &acc: accounts.keys()) { ui.accountsList->addItem(acc); } if (ui.accountsList->count() > 0) { ui.accountsList->setCurrentRow(0); updateTimelinesList(); } ui.backgroundColor->setColor(settings->backgroundColor()); ui.foregroundColor->setColor(settings->foregroundColor()); ui.font->setFont(settings->font()); } void NotifyConfig::save() { //qDebug()<< accounts.keys(); settings->setAccounts(accounts); settings->setNotifyInterval(ui.interval->value()); settings->setBackgroundColor(ui.backgroundColor->color()); settings->setForegroundColor(ui.foregroundColor->color()); settings->setFont(ui.font->font()); settings->save(); } void NotifyConfig::slotAdjustNotificationPosition() { ui.adjustPosition->setDisabled(true); if (!dummy) { dummy = new DummyNotification(ui.font->font(), ui.foregroundColor->color(), ui.backgroundColor->color(), this); dummy->setAttribute(Qt::WA_DeleteOnClose); dummy->resize(NOTIFICATION_WIDTH, NOTIFICATION_HEIGHT); - connect(dummy, SIGNAL(positionSelected(QPoint)), this, SLOT(slotNewPositionSelected(QPoint))); + connect(dummy, &DummyNotification::positionSelected, this, &NotifyConfig::slotNewPositionSelected); } dummy->move(settings->position()); dummy->show(); } void NotifyConfig::slotNewPositionSelected(QPoint pos) { settings->setPosition(pos); dummy->close(); ui.adjustPosition->setEnabled(true); emitChanged(); } #include "notifyconfig.moc" diff --git a/plugins/filter/addeditfilter.cpp b/plugins/filter/addeditfilter.cpp index b92b1599..22bcb314 100644 --- a/plugins/filter/addeditfilter.cpp +++ b/plugins/filter/addeditfilter.cpp @@ -1,121 +1,123 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "addeditfilter.h" +#include #include #include #include #include "filtersettings.h" AddEditFilter::AddEditFilter(QWidget *parent, Filter *filter) : QDialog(parent), currentFilter(filter) { ui.setupUi(this); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &AddEditFilter::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &AddEditFilter::reject); ui.formLayout->addWidget(buttonBox); - connect(ui.filterAction, SIGNAL(currentIndexChanged(int)), this, SLOT(slotFilterActionChanged(int))); + connect(ui.filterAction, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &AddEditFilter::slotFilterActionChanged); setupFilterFields(); setupFilterTypes(); setupFilterActions(); if (filter) { //qDebug() << filter->filterField(); //Editing ui.filterField->setCurrentIndex(ui.filterField->findData(filter->filterField())); ui.filterType->setCurrentIndex(ui.filterType->findData(filter->filterType())); ui.filterAction->setCurrentIndex(ui.filterAction->findData(filter->filterAction())); ui.filterText->setText(filter->filterText()); ui.dontHideReplies->setChecked(filter->dontHideReplies()); setWindowTitle(i18n("Modify filter rules")); } ui.filterText->setFocus(); } AddEditFilter::~AddEditFilter() { } void AddEditFilter::accept() { Filter::FilterField field = (Filter::FilterField) ui.filterField->itemData(ui.filterField->currentIndex()).toInt(); Filter::FilterType type = (Filter::FilterType) ui.filterType->itemData(ui.filterType->currentIndex()).toInt(); Filter::FilterAction action = (Filter::FilterAction) ui.filterAction->itemData(ui.filterAction->currentIndex()).toInt(); QString fText = ui.filterText->text(); bool dontHideReplies = ui.dontHideReplies->isChecked(); if (currentFilter) { currentFilter->setFilterField(field); currentFilter->setFilterText(fText); currentFilter->setFilterType(type); currentFilter->setFilterAction(action); currentFilter->setDontHideReplies(dontHideReplies); Q_EMIT filterUpdated(currentFilter); } else { currentFilter = new Filter(fText, field, type, action, dontHideReplies); Q_EMIT newFilterRegistered(currentFilter); } QDialog::accept(); } void AddEditFilter::slotFilterActionChanged(int index) { ui.dontHideReplies->setVisible((Filter::FilterAction)ui.filterAction->itemData(index).toInt() == Filter::Remove); } void AddEditFilter::setupFilterFields() { const QMap fields = FilterSettings::filterFieldsMap(); for (const Filter::FilterField &field: fields.keys()) { ui.filterField->addItem(fields.value(field), field); } } void AddEditFilter::setupFilterTypes() { const QMap types = FilterSettings::filterTypesMap(); for (const Filter::FilterType &type: types.keys()) { ui.filterType->addItem(types.value(type), type); } } void AddEditFilter::setupFilterActions() { const QMap actions = FilterSettings::filterActionsMap(); for (const Filter::FilterAction &action: actions.keys()) { ui.filterAction->addItem(actions.value(action), action); } } diff --git a/plugins/filter/configurefilters.cpp b/plugins/filter/configurefilters.cpp index 027c4736..a2b4b9dc 100644 --- a/plugins/filter/configurefilters.cpp +++ b/plugins/filter/configurefilters.cpp @@ -1,179 +1,180 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2009-2010 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "configurefilters.h" +#include #include #include #include #include #include "addeditfilter.h" #include "filtersettings.h" ConfigureFilters::ConfigureFilters(QWidget *parent): QDialog(parent) { QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); ui.setupUi(this); mainLayout->addLayout(ui.horizontalLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &ConfigureFilters::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &ConfigureFilters::reject); mainLayout->addWidget(buttonBox); resize(500, 300); - connect(ui.btnAdd, SIGNAL(clicked()), SLOT(slotAddFilter())); - connect(ui.btnEdit, SIGNAL(clicked()), SLOT(slotEditFilter())); - connect(ui.btnRemove, SIGNAL(clicked()), SLOT(slotRemoveFilter())); - connect(ui.cfg_hideRepliesNotRelatedToMe, SIGNAL(toggled(bool)), - this, SLOT(slotHideRepliesNotRelatedToMeToggled(bool))); + connect(ui.btnAdd, &QPushButton::clicked, this, &ConfigureFilters::slotAddFilter); + connect(ui.btnEdit, &QPushButton::clicked, this, &ConfigureFilters::slotEditFilter); + connect(ui.btnRemove, &QPushButton::clicked, this, &ConfigureFilters::slotRemoveFilter); + connect(ui.cfg_hideRepliesNotRelatedToMe, &QCheckBox::toggled, this, + &ConfigureFilters::slotHideRepliesNotRelatedToMeToggled); reloadFiltersTable(); } ConfigureFilters::~ConfigureFilters() { } void ConfigureFilters::accept() { saveFiltersTable(); QDialog::accept(); } void ConfigureFilters::reloadFiltersTable() { ui.filters->clearContents(); QList filters = FilterSettings::self()->filters(); //qDebug() << filters.count(); for (Filter *filter: filters) { addNewFilter(filter); } ui.cfg_hideNoneFriendsReplies->setChecked(FilterSettings::hideNoneFriendsReplies()); ui.cfg_hideRepliesNotRelatedToMe->setChecked(FilterSettings::hideRepliesNotRelatedToMe()); } void ConfigureFilters::saveFiltersTable() { QList list; int count = ui.filters->rowCount(); for (int i = 0; i < count; ++i) { Filter::FilterField field = (Filter::FilterField) ui.filters->item(i, 0)->data(32).toInt(); Filter::FilterType type = (Filter::FilterType) ui.filters->item(i, 1)->data(32).toInt(); Filter::FilterAction action = (Filter::FilterAction) ui.filters->item(i, 3)->data(32).toInt(); QString text = ui.filters->item(i, 2)->text(); bool dontHideReplies = ui.filters->item(i, 2)->data(32).toBool(); Filter *f = new Filter(text, field, type, action, dontHideReplies, FilterSettings::self()); list << f; } FilterSettings::self()->setFilters(list); FilterSettings::setHideNoneFriendsReplies(ui.cfg_hideNoneFriendsReplies->isChecked()); FilterSettings::setHideRepliesNotRelatedToMe(ui.cfg_hideRepliesNotRelatedToMe->isChecked()); FilterSettings::self()->writeConfig(); } void ConfigureFilters::slotAddFilter() { AddEditFilter *f = new AddEditFilter(this); - connect(f, SIGNAL(newFilterRegistered(Filter*)), SLOT(addNewFilter(Filter*))); + connect(f, &AddEditFilter::newFilterRegistered, this, &ConfigureFilters::addNewFilter); f->show(); } void ConfigureFilters::slotEditFilter() { if (ui.filters->selectedItems().count() > 0) { int row = ui.filters->currentRow(); Filter::FilterField field = (Filter::FilterField) ui.filters->item(row, 0)->data(32).toInt(); Filter::FilterType type = (Filter::FilterType) ui.filters->item(row, 1)->data(32).toInt(); Filter::FilterAction action = (Filter::FilterAction) ui.filters->item(row, 3)->data(32).toInt(); bool dontHideReplies = ui.filters->item(row, 2)->data(32).toBool(); QString text = ui.filters->item(row, 2)->text(); Filter *f = new Filter(text, field, type, action, dontHideReplies, this); QPointer dialog = new AddEditFilter(this, f); - connect(dialog, SIGNAL(filterUpdated(Filter*)), SLOT(slotUpdateFilter(Filter*))); + connect(dialog, &AddEditFilter::filterUpdated, this, &ConfigureFilters::slotUpdateFilter); dialog->exec(); } } void ConfigureFilters::slotRemoveFilter() { if (ui.filters->selectedItems().count() > 0) { int row = ui.filters->currentRow(); ui.filters->removeRow(row); } } void ConfigureFilters::addNewFilter(Filter *filter) { int row = ui.filters->rowCount(); ui.filters->insertRow(row); QTableWidgetItem *item1 = new QTableWidgetItem(FilterSettings::self()->filterFieldName(filter->filterField())); item1->setData(32, filter->filterField()); ui.filters->setItem(row, 0, item1); QTableWidgetItem *item2 = new QTableWidgetItem(FilterSettings::self()->filterTypeName(filter->filterType())); item2->setData(32, filter->filterType()); ui.filters->setItem(row, 1, item2); QTableWidgetItem *item3 = new QTableWidgetItem(filter->filterText()); item3->setData(32, filter->dontHideReplies()); ui.filters->setItem(row, 2, item3); QTableWidgetItem *item4 = new QTableWidgetItem(FilterSettings::self()->filterActionName(filter->filterAction())); item4->setData(32, filter->filterAction()); ui.filters->setItem(row, 3, item4); } void ConfigureFilters::slotUpdateFilter(Filter *filter) { int row = ui.filters->currentRow(); ui.filters->item(row, 0)->setText(FilterSettings::self()->filterFieldName(filter->filterField())); ui.filters->item(row, 0)->setData(32, filter->filterField()); ui.filters->item(row, 1)->setText(FilterSettings::self()->filterTypeName(filter->filterType())); ui.filters->item(row, 1)->setData(32, filter->filterType()); ui.filters->item(row, 2)->setText(filter->filterText()); ui.filters->item(row, 2)->setData(32, filter->dontHideReplies()); ui.filters->item(row, 3)->setText(FilterSettings::self()->filterActionName(filter->filterAction())); ui.filters->item(row, 3)->setData(32, filter->filterAction()); } void ConfigureFilters::slotHideRepliesNotRelatedToMeToggled(bool enabled) { if (enabled) { ui.cfg_hideNoneFriendsReplies->setChecked(false); ui.cfg_hideNoneFriendsReplies->setEnabled(false); } else { ui.cfg_hideNoneFriendsReplies->setEnabled(true); ui.cfg_hideNoneFriendsReplies->setChecked(FilterSettings::hideNoneFriendsReplies()); } } diff --git a/plugins/filter/filtermanager.cpp b/plugins/filter/filtermanager.cpp index 89316195..f6531375 100644 --- a/plugins/filter/filtermanager.cpp +++ b/plugins/filter/filtermanager.cpp @@ -1,265 +1,264 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "filtermanager.h" #include #include #include #include #include #include #include "choqokuiglobal.h" #include "postwidget.h" #include "quickpost.h" #include "timelinewidget.h" #include "twitterapiaccount.h" #include "configurefilters.h" #include "filter.h" #include "filtersettings.h" K_PLUGIN_FACTORY_WITH_JSON(FilterManagerFactory, "choqok_filter.json", registerPlugin < FilterManager > ();) FilterManager::FilterManager(QObject *parent, const QList &) : Choqok::Plugin(QLatin1String("choqok_filter"), parent), state(Stopped) { QAction *action = new QAction(i18n("Configure Filters..."), this); actionCollection()->addAction(QLatin1String("configureFilters"), action); - connect(action, SIGNAL(triggered(bool)), SLOT(slotConfigureFilters())); + connect(action, &QAction::triggered, this, &FilterManager::slotConfigureFilters); setXMLFile(QLatin1String("filterui.rc")); - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - SLOT(slotAddNewPostWidget(Choqok::UI::PostWidget*))); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &FilterManager::slotAddNewPostWidget); hidePost = new QAction(i18n("Hide Post"), this); Choqok::UI::PostWidget::addAction(hidePost); - connect(hidePost, SIGNAL(triggered(bool)), SLOT(slotHidePost())); + connect(hidePost, &QAction::triggered, this, &FilterManager::slotHidePost); } FilterManager::~FilterManager() { } void FilterManager::slotAddNewPostWidget(Choqok::UI::PostWidget *newWidget) { postsQueue.enqueue(newWidget); if (state == Stopped) { state = Running; QTimer::singleShot(1000, this, SLOT(startParsing())); } } void FilterManager::startParsing() { int i = 8; while (!postsQueue.isEmpty() && i > 0) { parse(postsQueue.dequeue()); --i; } if (postsQueue.isEmpty()) { state = Stopped; } else { QTimer::singleShot(500, this, SLOT(startParsing())); } } void FilterManager::parse(Choqok::UI::PostWidget *postToParse) { if (!postToParse || postToParse->currentPost()->author.userName == postToParse->currentAccount()->username() || postToParse->isRead()) { return; } if (parseSpecialRules(postToParse)) { return; } if (!postToParse) { return; } //qDebug() << "Processing: "<content(); for (Filter *filter: FilterSettings::self()->filters()) { if (filter->filterText().isEmpty()) { return; } if (filter->filterAction() == Filter::Remove && filter->dontHideReplies() && (postToParse->currentPost()->replyToUser.userName.compare(postToParse->currentAccount()->username(), Qt::CaseInsensitive) == 0 || postToParse->currentPost()->content.contains(QStringLiteral("@%1").arg(postToParse->currentAccount()->username()))) ) { continue; } switch (filter->filterField()) { case Filter::Content: doFiltering(postToParse, filterText(postToParse->currentPost()->content, filter)); break; case Filter::AuthorUsername: doFiltering(postToParse, filterText(postToParse->currentPost()->author.userName, filter)); break; case Filter::ReplyToUsername: doFiltering(postToParse, filterText(postToParse->currentPost()->replyToUser.userName, filter)); break; case Filter::Source: doFiltering(postToParse, filterText(postToParse->currentPost()->source, filter)); break; default: break; }; } } Filter::FilterAction FilterManager::filterText(const QString &textToCheck, Filter *filter) { bool filtered = false; switch (filter->filterType()) { case Filter::ExactMatch: if (textToCheck.compare(filter->filterText(), Qt::CaseInsensitive) == 0) { //qDebug() << "ExactMatch:" << filter->filterText(); filtered = true; } break; case Filter::RegExp: if (textToCheck.contains(QRegExp(filter->filterText()))) { //qDebug() << "RegExp:" << filter->filterText(); filtered = true; } break; case Filter::Contain: if (textToCheck.contains(filter->filterText(), Qt::CaseInsensitive)) { //qDebug() << "Contain:" << filter->filterText(); filtered = true; } break; case Filter::DoesNotContain: if (!textToCheck.contains(filter->filterText(), Qt::CaseInsensitive)) { //qDebug() << "DoesNotContain:" << filter->filterText(); filtered = true; } break; default: break; } if (filtered) { return filter->filterAction(); } else { return Filter::None; } } void FilterManager::doFiltering(Choqok::UI::PostWidget *postToFilter, Filter::FilterAction action) { QString css; switch (action) { case Filter::Remove: //qDebug() << "Post removed:" << postToFilter->currentPost()->content; postToFilter->close(); break; case Filter::Highlight: css = postToFilter->styleSheet(); css.replace(QLatin1String("border: 1px solid rgb(150,150,150)"), QLatin1String("border: 2px solid rgb(255,0,0)")); postToFilter->setStyleSheet(css); break; case Filter::None: default: //Do nothing break; } } void FilterManager::slotConfigureFilters() { QPointer dlg = new ConfigureFilters(Choqok::UI::Global::mainWindow()); dlg->show(); } bool FilterManager::parseSpecialRules(Choqok::UI::PostWidget *postToParse) { if (FilterSettings::hideRepliesNotRelatedToMe()) { if (!postToParse->currentPost()->replyToUser.userName.isEmpty() && postToParse->currentPost()->replyToUser.userName != postToParse->currentAccount()->username()) { if (!postToParse->currentPost()->content.contains(postToParse->currentAccount()->username())) { postToParse->close(); // qDebug() << "NOT RELATE TO ME FILTERING......"; return true; } } } if (FilterSettings::hideNoneFriendsReplies()) { TwitterApiAccount *acc = qobject_cast(postToParse->currentAccount()); if (!acc) { return false; } if (!postToParse->currentPost()->replyToUser.userName.isEmpty() && !acc->friendsList().contains(postToParse->currentPost()->replyToUser.userName)) { if (!postToParse->currentPost()->content.contains(postToParse->currentAccount()->username())) { postToParse->close(); // qDebug() << "NONE FRIEND FILTERING......"; return true; } } } return false; } void FilterManager::slotHidePost() { Choqok::UI::PostWidget *wd; wd = dynamic_cast(hidePost->userData(32))->postWidget(); QString username = wd->currentPost()->author.userName; int res = KMessageBox::questionYesNoCancel(choqokMainWindow, i18n("Hide all posts from @%1?", username)); if (res == KMessageBox::Cancel) { return; } else if (res == KMessageBox::Yes) { Filter *fil = new Filter(username, Filter::AuthorUsername, Filter::ExactMatch); fil->writeConfig(); QList filterList = FilterSettings::self()->filters(); filterList.append(fil); FilterSettings::self()->setFilters(filterList); Choqok::UI::TimelineWidget *tm = wd->timelineWidget(); if (tm) { // qDebug() << "Closing all posts"; for (Choqok::UI::PostWidget *pw: tm->postWidgets()) { if (pw->currentPost()->author.userName == username) { pw->close(); } } } else { wd->close(); } } else { wd->close(); } } #include "filtermanager.moc" diff --git a/plugins/imagepreview/imagepreview.cpp b/plugins/imagepreview/imagepreview.cpp index 67071c29..373441dd 100644 --- a/plugins/imagepreview/imagepreview.cpp +++ b/plugins/imagepreview/imagepreview.cpp @@ -1,166 +1,162 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "imagepreview.h" #include #include #include "choqokuiglobal.h" #include "mediamanager.h" #include "postwidget.h" #include "textbrowser.h" K_PLUGIN_FACTORY_WITH_JSON(ImagePreviewFactory, "choqok_imagepreview.json", registerPlugin < ImagePreview > ();) const QRegExp ImagePreview::mImgLyRegExp(QLatin1String("(http://img.ly/[^\\s<>\"]+[^!,\\.\\s<>'\"\\]])")); const QRegExp ImagePreview::mTwitgooRegExp(QLatin1String("(http://(([a-zA-Z0-9]+\\.)?)twitgoo.com/[^\\s<>\"]+[^!,\\.\\s<>'\"\\]])")); const QRegExp ImagePreview::mPumpIORegExp(QLatin1String("(https://([a-zA-Z0-9]+\\.)?[a-zA-Z0-9]+\\.[a-zA-Z]+/uploads/\\w+/\\d{4}/\\d{1,2}/\\d{1,2}/\\w+)(\\.[a-zA-Z]{3,4})")); ImagePreview::ImagePreview(QObject *parent, const QList< QVariant > &) : Choqok::Plugin(QLatin1String("choqok_imagepreview"), parent), state(Stopped) { - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - this, - SLOT(slotAddNewPostWidget(Choqok::UI::PostWidget*))); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &ImagePreview::slotAddNewPostWidget); } ImagePreview::~ImagePreview() { } void ImagePreview::slotAddNewPostWidget(Choqok::UI::PostWidget *newWidget) { postsQueue.enqueue(newWidget); if (state == Stopped) { state = Running; QTimer::singleShot(1000, this, SLOT(startParsing())); } } void ImagePreview::startParsing() { int i = 8; while (!postsQueue.isEmpty() && i > 0) { parse(postsQueue.dequeue()); --i; } if (postsQueue.isEmpty()) { state = Stopped; } else { QTimer::singleShot(500, this, SLOT(startParsing())); } } void ImagePreview::parse(Choqok::UI::PostWidget *postToParse) { if (!postToParse) { return; } int pos = 0; QStringList ImgLyRedirectList; QStringList TwitgooRedirectList; QStringList PumpIORedirectList; QString content = postToParse->currentPost()->content; //Img.ly; http://img.ly/api/docs pos = 0; while ((pos = mImgLyRegExp.indexIn(content, pos)) != -1) { pos += mImgLyRegExp.matchedLength(); ImgLyRedirectList << mImgLyRegExp.cap(0); } for (const QString &url: ImgLyRedirectList) { - connect(Choqok::MediaManager::self(), - SIGNAL(imageFetched(QUrl,QPixmap)), - SLOT(slotImageFetched(QUrl,QPixmap))); + connect(Choqok::MediaManager::self(),&Choqok::MediaManager::imageFetched, + this, &ImagePreview::slotImageFetched); QUrl ImgLyUrl = QUrl::fromUserInput(QStringLiteral("http://img.ly/show/thumb%1").arg(QString(url).remove(QLatin1String("http://img.ly")))); mParsingList.insert(ImgLyUrl, postToParse); mBaseUrlMap.insert(ImgLyUrl, url); Choqok::MediaManager::self()->fetchImage(ImgLyUrl, Choqok::MediaManager::Async); } //Twitgoo; http://twitgoo.com/docs/TwitgooHelp.htm pos = 0; while ((pos = mTwitgooRegExp.indexIn(content, pos)) != -1) { pos += mTwitgooRegExp.matchedLength(); TwitgooRedirectList << mTwitgooRegExp.cap(0); } for (const QString &url: TwitgooRedirectList) { - connect(Choqok::MediaManager::self(), - SIGNAL(imageFetched(QUrl,QPixmap)), - SLOT(slotImageFetched(QUrl,QPixmap))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &ImagePreview::slotImageFetched); QUrl TwitgooUrl = QUrl::fromUserInput(url + QLatin1String("/thumb")); mParsingList.insert(TwitgooUrl, postToParse); mBaseUrlMap.insert(TwitgooUrl, url); Choqok::MediaManager::self()->fetchImage(TwitgooUrl, Choqok::MediaManager::Async); } //PumpIO pos = 0; QString baseUrl; QString imageExtension; while ((pos = mPumpIORegExp.indexIn(content, pos)) != -1) { pos += mPumpIORegExp.matchedLength(); PumpIORedirectList << mPumpIORegExp.cap(0); baseUrl = mPumpIORegExp.cap(1); imageExtension = mPumpIORegExp.cap(mPumpIORegExp.capturedTexts().length() - 1); } for (const QString &url: PumpIORedirectList) { - connect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - SLOT(slotImageFetched(QUrl,QPixmap))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &ImagePreview::slotImageFetched); const QUrl pumpIOUrl = QUrl::fromUserInput(baseUrl + QLatin1String("_thumb") + imageExtension); mParsingList.insert(pumpIOUrl, postToParse); mBaseUrlMap.insert(pumpIOUrl, url); Choqok::MediaManager::self()->fetchImage(pumpIOUrl, Choqok::MediaManager::Async); } } void ImagePreview::slotImageFetched(const QUrl &remoteUrl, const QPixmap &pixmap) { Choqok::UI::PostWidget *postToParse = mParsingList.take(remoteUrl); QString baseUrl = mBaseUrlMap.take(remoteUrl); if (!postToParse) { return; } QString content = postToParse->content(); QUrl imgU(remoteUrl); imgU.setScheme(QLatin1String("img")); // imgUrl.replace("http://","img://"); QPixmap pix = pixmap; if (pixmap.width() > 200) { pix = pixmap.scaledToWidth(200); } else if (pixmap.height() > 200) { pix = pixmap.scaledToHeight(200); } postToParse->mainWidget()->document()->addResource(QTextDocument::ImageResource, imgU, pix); content.replace(QRegExp(QLatin1Char('>') + baseUrl + QLatin1Char('<')), QStringLiteral("><")); postToParse->setContent(content); } #include "imagepreview.moc" diff --git a/plugins/imstatus/imqdbus.cpp b/plugins/imstatus/imqdbus.cpp index ce117901..40123327 100644 --- a/plugins/imstatus/imqdbus.cpp +++ b/plugins/imstatus/imqdbus.cpp @@ -1,246 +1,247 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "imqdbus.h" #include #include #include #include #ifdef TELEPATHY_FOUND #include #include #include #include #include #endif const QString IM_KOPETE = QLatin1String("Kopete"); const QString IM_PSI = QLatin1String("Psi"); const QString IM_SKYPE = QLatin1String("Skype"); const QString IM_PIDGIN = QLatin1String("Pidgin"); const QString IM_TELEPATHY = QLatin1String("Telepathy"); IMQDBus::IMQDBus(QObject *parent) : QObject(parent) { /* TODO: - qutIM (>0.3) - gajim ( doesn't want work :( ) */ #ifdef TELEPATHY_FOUND m_accountManager = Tp::AccountManager::create(Tp::AccountFactory::create(QDBusConnection::sessionBus(), Tp::Account::FeatureCore)); - connect(m_accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(slotFinished(Tp::PendingOperation*))); + connect(m_accountManager->becomeReady(), &Tp::PendingOperation::finished, + this, &IMQDBus::slotFinished);; Tp::registerTypes(); #endif } void IMQDBus::updateStatusMessage(const QString &im, const QString &statusMessage) { if (im == IM_KOPETE) { useKopete(statusMessage); } if (im == IM_PSI) { usePsi(statusMessage); } if (im == IM_SKYPE) { useSkype(statusMessage); } if (im == IM_PIDGIN) { usePidgin(statusMessage); } #ifdef TELEPATHY_FOUND if (im == IM_TELEPATHY) { useTelepathy(statusMessage); } #endif } void IMQDBus::useKopete(const QString &statusMessage) { QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String("org.kde.kopete"), QLatin1String("/Kopete"), QLatin1String("org.kde.Kopete"), QLatin1String("setStatusMessage")); QList args; args.append(QVariant(statusMessage)); msg.setArguments(args); QDBusMessage rep = QDBusConnection::sessionBus().call(msg); if (rep.type() == QDBusMessage::ErrorMessage) { qWarning() << "Failed with error:" << rep.errorMessage(); return; } } void IMQDBus::usePsi(const QString &statusMessage) { QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String("org.psi-im.Psi"), QLatin1String("/Main"), QLatin1String("org.psi_im.Psi.Main"), QLatin1String("setStatus")); QList args; args.append(QVariant(QLatin1String("online"))); args.append(QVariant(statusMessage)); msg.setArguments(args); QDBusMessage rep = QDBusConnection::sessionBus().call(msg); if (rep.type() == QDBusMessage::ErrorMessage) { qWarning() << "Failed with error:" << rep.errorMessage(); return; } } void IMQDBus::useSkype(const QString &statusMessage) { QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String("com.Skype.API"), QLatin1String("/com/Skype"), QLatin1String("com.Skype.API"), QLatin1String("Invoke")); QList args; args.append(QVariant(QLatin1String("NAME Choqok"))); msg.setArguments(args); QDBusMessage rep = QDBusConnection::sessionBus().call(msg); if (rep.type() == QDBusMessage::ErrorMessage) { qWarning() << "Failed with error:" << rep.errorMessage(); return; } args.clear(); args.append(QVariant(QLatin1String("PROTOCOL 7"))); msg.setArguments(args); rep = QDBusConnection::sessionBus().call(msg); if (rep.type() == QDBusMessage::ErrorMessage) { qWarning() << "Failed with error:" << rep.errorMessage(); return; } args.clear(); args.append(QVariant(QStringLiteral("SET PROFILE MOOD_TEXT %1").arg(statusMessage))); msg.setArguments(args); rep = QDBusConnection::sessionBus().call(msg); if (rep.type() == QDBusMessage::ErrorMessage) { qWarning() << "Failed with error:" << rep.errorMessage(); return; } } void IMQDBus::usePidgin(const QString &statusMessage) { QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String("im.pidgin.purple.PurpleService"), QLatin1String("/im/pidgin/purple/PurpleObject"), QLatin1String("im.pidgin.purple.PurpleInterface"), QLatin1String("PurpleSavedstatusGetCurrent")); QDBusReply repUInt = QDBusConnection::sessionBus().call(msg); if (repUInt.error().isValid()) { qWarning() << "Failed with error:" << repUInt.error().message(); return; } int IDCurrentStatus = repUInt.value(); msg = QDBusMessage::createMethodCall(QLatin1String("im.pidgin.purple.PurpleService"), QLatin1String("/im/pidgin/purple/PurpleObject"), QLatin1String("im.pidgin.purple.PurpleInterface"), QLatin1String("PurpleSavedstatusGetType")); QList args; args.append(QVariant(IDCurrentStatus)); msg.setArguments(args); repUInt = QDBusConnection::sessionBus().call(msg); if (repUInt.error().isValid()) { qWarning() << "Failed with error:" << repUInt.error().message(); return; } int currentStatusType = repUInt.value(); msg = QDBusMessage::createMethodCall(QLatin1String("im.pidgin.purple.PurpleService"), QLatin1String("/im/pidgin/purple/PurpleObject"), QLatin1String("im.pidgin.purple.PurpleInterface"), QLatin1String("PurpleSavedstatusNew")); args.clear(); args.append(QVariant(QString())); args.append(QVariant(currentStatusType)); msg.setArguments(args); repUInt = QDBusConnection::sessionBus().call(msg); if (repUInt.error().isValid()) { qWarning() << "Failed with error:" << repUInt.error().message(); return; } IDCurrentStatus = repUInt.value(); //ID of new status msg = QDBusMessage::createMethodCall(QLatin1String("im.pidgin.purple.PurpleService"), QLatin1String("/im/pidgin/purple/PurpleObject"), QLatin1String("im.pidgin.purple.PurpleInterface"), QLatin1String("PurpleSavedstatusSetMessage")); args.clear(); args.append(QVariant(IDCurrentStatus)); args.append(QVariant(statusMessage)); msg.setArguments(args); QDBusReply repStr = QDBusConnection::sessionBus().call(msg); if (repStr.error().isValid()) { qWarning() << "Failed with error:" << repStr.error().message(); return; } msg = QDBusMessage::createMethodCall(QLatin1String("im.pidgin.purple.PurpleService"), QLatin1String("/im/pidgin/purple/PurpleObject"), QLatin1String("im.pidgin.purple.PurpleInterface"), QLatin1String("PurpleSavedstatusActivate")); args.clear(); args.append(QVariant(IDCurrentStatus)); msg.setArguments(args); repStr = QDBusConnection::sessionBus().call(msg); if (repStr.error().isValid()) { qWarning() << "Failed with error:" << repStr.error().message(); return; } } #ifdef TELEPATHY_FOUND void IMQDBus::useTelepathy(const QString &statusMessage) { if (m_accountManager->isReady()) { Tp::AccountSetPtr validAccountsPtr = m_accountManager->enabledAccounts(); QList accountsList = validAccountsPtr->accounts(); for (const Tp::AccountPtr &account: accountsList) { if (account->isOnline() && account->isReady()) { Tp::Presence currentPresence = account->currentPresence(); currentPresence.setStatusMessage(statusMessage); account->setRequestedPresence(currentPresence); } } } } void IMQDBus::slotFinished(Tp::PendingOperation *po) { if (po->isError()) { qCritical() << "Telepathy AccountManager failed to get ready:" << po->errorMessage(); } } #endif IMQDBus::~IMQDBus() {} QStringList IMQDBus::scanForIMs() { QStringList ims; if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("com.Skype.API")).value()) { ims << IM_SKYPE; } if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.psi-im.Psi")).value()) { ims << IM_PSI; } if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.kopete")).value()) { ims << IM_KOPETE; } if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("im.pidgin.purple.PurpleService")).value()) { ims << IM_PIDGIN; } #ifdef TELEPATHY_FOUND if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.freedesktop.Telepathy.AccountManager")).value()) { ims << IM_TELEPATHY; } #endif ims.sort(); return ims; } diff --git a/plugins/imstatus/imstatus.cpp b/plugins/imstatus/imstatus.cpp index ce8c8186..065e56d0 100644 --- a/plugins/imstatus/imstatus.cpp +++ b/plugins/imstatus/imstatus.cpp @@ -1,89 +1,89 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "imstatus.h" #include #include #include "choqokuiglobal.h" #include "quickpost.h" #include "imqdbus.h" #include "imstatussettings.h" K_PLUGIN_FACTORY_WITH_JSON(IMStatusFactory, "choqok_imstatus.json", registerPlugin < IMStatus > ();) class IMStatusPrivate { public: IMStatusPrivate() {} IMQDBus *im; }; IMStatus::IMStatus(QObject *parent, const QList &) : Choqok::Plugin(QLatin1String("choqok_imstatus"), parent), d(new IMStatusPrivate()) { QTimer::singleShot(500, this, SLOT(update())); d->im = new IMQDBus(this); } IMStatus::~IMStatus() { delete d; } void IMStatus::update() { if (Choqok::UI::Global::quickPostWidget() != 0) { - connect(Choqok::UI::Global::quickPostWidget(), SIGNAL(newPostSubmitted(Choqok::JobResult,Choqok::Post*)), - this, SLOT(slotIMStatus(Choqok::JobResult,Choqok::Post*))); + connect(Choqok::UI::Global::quickPostWidget(), &Choqok::UI::QuickPost::newPostSubmitted, + this, &IMStatus::slotIMStatus); } else { QTimer::singleShot(500, this, SLOT(update())); } } void IMStatus::slotIMStatus(Choqok::JobResult res, Choqok::Post *newPost) { if (res == Choqok::Success) { IMStatusSettings::self()->load(); QString statusMessage = IMStatusSettings::templtate(); statusMessage.replace(QLatin1String("%status%"), newPost->content, Qt::CaseInsensitive); statusMessage.replace(QLatin1String("%username%"), newPost->author.userName, Qt::CaseInsensitive); statusMessage.replace(QLatin1String("%fullname%"), newPost->author.realName, Qt::CaseInsensitive); statusMessage.replace(QLatin1String("%time%"), newPost->creationDateTime.toString(QLatin1String("hh:mm:ss")), Qt::CaseInsensitive); statusMessage.replace(QLatin1String("%url%"), newPost->link.toDisplayString(), Qt::CaseInsensitive); statusMessage.replace(QLatin1String("%client%"), QLatin1String("Choqok"), Qt::CaseInsensitive); if (!IMStatusSettings::repeat() && !newPost->repeatedFromUser.userName.isEmpty()) { return; } if (!IMStatusSettings::reply() && !newPost->replyToUser.userName.isEmpty()) { return; } d->im->updateStatusMessage(IMStatusSettings::imclient(), statusMessage); } } #include "imstatus.moc" diff --git a/plugins/imstatus/imstatusconfig.cpp b/plugins/imstatus/imstatusconfig.cpp index c757872b..e16b15bb 100644 --- a/plugins/imstatus/imstatusconfig.cpp +++ b/plugins/imstatus/imstatusconfig.cpp @@ -1,86 +1,90 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "imstatusconfig.h" +#include +#include +#include #include #include #include #include "imqdbus.h" #include "imstatussettings.h" K_PLUGIN_FACTORY_WITH_JSON(IMStatusConfigFactory, "choqok_imstatus_config.json", registerPlugin < IMStatusConfig > ();) IMStatusConfig::IMStatusConfig(QWidget *parent, const QVariantList &args) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_imstatus")), parent, args) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mIMStatusCtl")); ui.setupUi(wd); addConfig(IMStatusSettings::self(), wd); layout->addWidget(wd); setButtons(KCModule::Apply); - connect(ui.cfg_imclient, SIGNAL(currentIndexChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_repeat, SIGNAL(stateChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_reply, SIGNAL(stateChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_templtate, SIGNAL(textChanged()), SLOT(emitChanged())); + connect(ui.cfg_imclient, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &IMStatusConfig::emitChanged); + connect(ui.cfg_repeat, &QCheckBox::stateChanged, this, &IMStatusConfig::emitChanged); + connect(ui.cfg_reply, &QCheckBox::stateChanged, this, &IMStatusConfig::emitChanged); + connect(ui.cfg_templtate, &QPlainTextEdit::textChanged, this, &IMStatusConfig::emitChanged); imList = IMQDBus::scanForIMs(); ui.cfg_imclient->addItems(imList); } IMStatusConfig::~IMStatusConfig() { } void IMStatusConfig::load() { KCModule::load(); KConfigGroup grp(KSharedConfig::openConfig(), "IMStatus"); IMStatusSettings::self()->load(); ui.cfg_imclient->setCurrentIndex(imList.indexOf(IMStatusSettings::imclient())); ui.cfg_templtate->setPlainText(IMStatusSettings::templtate().isEmpty() ? QLatin1String("%username%: \"%status%\" at %time% from %client% (%url%)") : IMStatusSettings::templtate()); ui.cfg_reply->setChecked(IMStatusSettings::reply()); ui.cfg_repeat->setChecked(IMStatusSettings::repeat()); } void IMStatusConfig::save() { KCModule::save(); IMStatusSettings::setImclient(ui.cfg_imclient->currentText()); IMStatusSettings::setTempltate(ui.cfg_templtate->toPlainText()); IMStatusSettings::setReply(ui.cfg_reply->isChecked()); IMStatusSettings::setRepeat(ui.cfg_repeat->isChecked()); IMStatusSettings::self()->save(); } void IMStatusConfig::emitChanged() { Q_EMIT changed(true); } #include "imstatusconfig.moc" diff --git a/plugins/nowlistening/nowlistening.cpp b/plugins/nowlistening/nowlistening.cpp index a8cf34a1..26bb5998 100644 --- a/plugins/nowlistening/nowlistening.cpp +++ b/plugins/nowlistening/nowlistening.cpp @@ -1,264 +1,264 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny Copyright (C) 2010-2011 Ramin Gomari This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "nowlistening.h" #include #include #include #include #include #include #include #include #include "choqokuiglobal.h" #include "nowlisteningsettings.h" #include "quickpost.h" #include "mpris.h" K_PLUGIN_FACTORY_WITH_JSON(NowListeningFactory, "choqok_nowlistening.json", registerPlugin < NowListening > ();) NowListening::NowListening(QObject *parent, const QList &) : Choqok::Plugin(QLatin1String("choqok_nowlistening"), parent) { QAction *action = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")), i18n("Now Listening"), this); actionCollection()->addAction(QLatin1String("nowListening"), action); - connect(action, SIGNAL(triggered(bool)), SLOT(slotPrepareNowListening())); + connect(action, &QAction::triggered, this, &NowListening::slotPrepareNowListening); setXMLFile(QLatin1String("nowlisteningui.rc")); } NowListening::~NowListening() { } void NowListening::slotPrepareNowListening() { QVariantMap trackInfo; QString player; bool playerFound = false; bool isPlaying = false; MPRIS amarok(QLatin1String("amarok")); if (amarok.isValid()) { if (amarok.isPlaying()) { trackInfo = amarok.getTrackMetadata(); isPlaying = true; } playerFound = true; player = QLatin1String("Amarok"); } MPRIS audacious(QLatin1String("audacious")); if (!isPlaying && audacious.isValid()) { if (audacious.isPlaying()) { trackInfo = audacious.getTrackMetadata(); isPlaying = true; } playerFound = true; player = QLatin1String("Audacious"); } // MPRIS id of Dragon Player contain pid of it. QStringList playersList = MPRIS::getRunningPlayers(); if (!playersList.isEmpty() && playersList.indexOf(QRegExp(QLatin1String("dragonplayer(.*)"))) > -1) { int i = playersList.indexOf(QRegExp(QLatin1String("dragonplayer(.*)"))); MPRIS dragon(playersList.at(i)); if (!isPlaying && dragon.isValid()) { if (dragon.isPlaying()) { trackInfo = dragon.getTrackMetadata(); isPlaying = true; } playerFound = true; player = QLatin1String("Dragon Player"); } } //need to enable MPRIS Plugin (Qmmp +0.4) MPRIS qmmp(QLatin1String("qmmp")); if (!isPlaying && qmmp.isValid()) { if (qmmp.isPlaying()) { trackInfo = qmmp.getTrackMetadata(); isPlaying = true; } playerFound = true; player = QLatin1String("Qmmp"); } // only works if enabled D-BUS control interface in VLC (VLC 0.9.0+) MPRIS vlc(QLatin1String("vlc")); if (!isPlaying && vlc.isValid()) { if (vlc.isPlaying()) { trackInfo = vlc.getTrackMetadata(); isPlaying = true; } playerFound = true; player = QLatin1String("VLC"); } //Mpris not complete supported by Kaffeine Version 1.0-svn3 /* MPRIS kaffeine("kaffeine"); if(!isPlaying && kaffeine.isValid()){ if(kaffeine.isPlaying()){ trackInfo=kaffeine.getTrackMetadata(); isPlaying=true; } playerFound=true; player="Kaffeine"; } */ if (!isPlaying && QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.juk")).value()) { QDBusInterface jukPlayer(QLatin1String("org.kde.juk"), QLatin1String("/Player"), QLatin1String("org.kde.juk.player")); if (((QDBusReply)jukPlayer.call(QLatin1String("playing"))).value()) { QDBusReply< QString> reply = jukPlayer.call(QLatin1String("trackProperty"), QLatin1String("Title")); trackInfo.insert(QLatin1String("title"), reply.value()); reply = jukPlayer.call(QLatin1String("trackProperty"), QLatin1String("Track")); trackInfo.insert(QLatin1String("track"), reply.value()); reply = jukPlayer.call(QLatin1String("trackProperty"), QLatin1String("Album")); trackInfo.insert(QLatin1String("album"), reply.value()); reply = jukPlayer.call(QLatin1String("trackProperty"), QLatin1String("Artist")); trackInfo.insert(QLatin1String("artist"), reply.value()); reply = jukPlayer.call(QLatin1String("trackProperty"), QLatin1String("Year")); trackInfo.insert(QLatin1String("year"), reply.value()); reply = jukPlayer.call(QLatin1String("trackProperty"), QLatin1String("Genre")); trackInfo.insert(QLatin1String("genre"), reply.value()); isPlaying = true; } playerFound = true; player = QLatin1String("JuK"); } if (!isPlaying && QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.gnome.Rhythmbox")).value()) { QDBusInterface rhythmboxPlayer(QLatin1String("org.gnome.Rhythmbox") , QLatin1String("/org/gnome/Rhythmbox/Player"), QLatin1String("org.gnome.Rhythmbox.Player")); if (((QDBusReply)rhythmboxPlayer.call(QLatin1String("getPlaying"))).value()) { QDBusReply uri = rhythmboxPlayer.call(QLatin1String("getPlayingUri")); QDBusInterface rhythmboxShell(QLatin1String("org.gnome.Rhythmbox") , QLatin1String("/org/gnome/Rhythmbox/Shell"), QLatin1String("org.gnome.Rhythmbox.Shell")); QDBusReply< QMap > reply = rhythmboxShell.call(QLatin1String("getSongProperties"), uri.value()); trackInfo = reply.value(); isPlaying = true; } playerFound = true; player = QLatin1String("Rhythmbox"); } if (!isPlaying && QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.exaile.Exaile")).value()) { QDBusInterface exailePlayer(QLatin1String("org.exaile.Exaile"), QLatin1String("/org/exaile/Exaile"), QLatin1String("org.exaile.Exaile")); if (((QDBusReply) exailePlayer.call(QLatin1String("IsPlaying"))).value()) { QDBusReply reply = exailePlayer.call(QLatin1String("GetTrackAttr"), QLatin1String("tracknumber")); trackInfo.insert(QLatin1String("tracknumber"), reply.value()); reply = exailePlayer.call(QLatin1String("GetTrackAttr"), QLatin1String("title")); trackInfo.insert(QLatin1String("title"), reply.value()); reply = exailePlayer.call(QLatin1String("GetTrackAttr"), QLatin1String("album")); trackInfo.insert(QLatin1String("album"), reply.value()); reply = exailePlayer.call(QLatin1String("GetTrackAttr"), QLatin1String("artist")); trackInfo.insert(QLatin1String("artist"), reply.value()); reply = exailePlayer.call(QLatin1String("GetTrackAttr"), QLatin1String("year")); trackInfo.insert(QLatin1String("year"), reply.value()); reply = exailePlayer.call(QLatin1String("GetTrackAttr"), QLatin1String("genre")); trackInfo.insert(QLatin1String("genre"), reply.value()); isPlaying = true; } playerFound = true; player = QLatin1String("Exaile"); } if (!isPlaying && QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.bansheeproject.Banshee")).value()) { // provide for new interface in Banshee 1.0+ QDBusInterface bansheePlayer(QLatin1String("org.bansheeproject.Banshee"), QLatin1String("/org/bansheeproject/Banshee/PlayerEngine"), QLatin1String("org.bansheeproject.Banshee.PlayerEngine")); if (!((QDBusReply) bansheePlayer.call(QLatin1String("GetCurrentState"))).value().compare(QLatin1String("playing"))) { QDBusReply< QMap > reply = bansheePlayer.call(QLatin1String("GetCurrentTrack")); trackInfo = reply.value(); trackInfo.insert(QLatin1String("title"), trackInfo[QLatin1String("name")]); isPlaying = true; } playerFound = true; player = QLatin1String("Banshee"); } //trying to find not supported players that implamented the MPRIS-Dbus interface if (!isPlaying && !MPRIS::getRunningPlayers().isEmpty()) { for (const QString &playerName: MPRIS::getRunningPlayers()) { playerFound = true; MPRIS mprisPlayer(playerName); if (mprisPlayer.isValid() && mprisPlayer.isPlaying()) { trackInfo = mprisPlayer.getTrackMetadata(); isPlaying = true; player = mprisPlayer.getPlayerIdentification().left( mprisPlayer.getPlayerIdentification().lastIndexOf(QLatin1Char(' '))); //remove the version of player break; } } } if (!isPlaying) { if (playerFound) KMessageBox::information(Choqok::UI::Global::mainWindow(), i18nc("Player is running, But it's not playing.", "Play your desired music player.")); else KMessageBox::sorry(Choqok::UI::Global::mainWindow(), i18n("No supported player found.")); return; } NowListeningSettings::self()->load(); QString text = NowListeningSettings::templateString(); text.replace(QLatin1String("%track%"), trackInfo[QLatin1String("tracknumber")].toString()); text.replace(QLatin1String("%title%"), trackInfo[QLatin1String("title")].toString()); text.replace(QLatin1String("%album%"), trackInfo[QLatin1String("album")].toString()); text.replace(QLatin1String("%artist%"), trackInfo[QLatin1String("artist")].toString()); text.replace(QLatin1String("%year%"), trackInfo[QLatin1String("year")].toString()); text.replace(QLatin1String("%genre%"), trackInfo[QLatin1String("genre")].toString()); text.replace(QLatin1String("%player%"), player); if (Choqok::UI::Global::quickPostWidget()) { Choqok::UI::Global::quickPostWidget()->setText(text); } } #include "nowlistening.moc" diff --git a/plugins/nowlistening/nowlisteningconfig.cpp b/plugins/nowlistening/nowlisteningconfig.cpp index e13291f2..acc21563 100644 --- a/plugins/nowlistening/nowlisteningconfig.cpp +++ b/plugins/nowlistening/nowlisteningconfig.cpp @@ -1,75 +1,78 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2009-2010 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "nowlisteningconfig.h" +#include #include #include #include #include "nowlisteningsettings.h" K_PLUGIN_FACTORY_WITH_JSON(NowListeningConfigFactory, "choqok_nowlistening_config.json", registerPlugin < NowListeningConfig > ();) NowListeningConfig::NowListeningConfig(QWidget *parent, const QVariantList &args) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_nowlistening")), parent, args) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mNowListeningCtl")); ui.setupUi(wd); addConfig(NowListeningSettings::self(), wd); layout->addWidget(wd); setButtons(KCModule::Apply | KCModule::Default); - connect(ui.kcfg_templateString, SIGNAL(textChanged()), SLOT(emitChanged())); + connect(ui.kcfg_templateString, &QPlainTextEdit::textChanged, + this, &NowListeningConfig::emitChanged); } NowListeningConfig::~NowListeningConfig() { } void NowListeningConfig::defaults() { KCModule::defaults(); } void NowListeningConfig::load() { KCModule::load(); } void NowListeningConfig::save() { KCModule::save(); } void NowListeningConfig::emitChanged() { Q_EMIT changed(true); - disconnect(ui.kcfg_templateString, SIGNAL(textChanged()), this, SLOT(emitChanged())); + disconnect(ui.kcfg_templateString, &QPlainTextEdit::textChanged, + this, &NowListeningConfig::emitChanged); } #include "nowlisteningconfig.moc" diff --git a/plugins/quickfilter/quickfilter.cpp b/plugins/quickfilter/quickfilter.cpp index 3f05deab..df9d4617 100644 --- a/plugins/quickfilter/quickfilter.cpp +++ b/plugins/quickfilter/quickfilter.cpp @@ -1,225 +1,224 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2011-2012 Mehrdad Momeny Copyright (C) 2011 Farhad Hedayati-Fard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "quickfilter.h" #include #include #include #include #include #include #include #include #include "choqoktypes.h" #include "choqokuiglobal.h" #include "microblogwidget.h" #include "postwidget.h" #include "quickpost.h" #include "timelinewidget.h" K_PLUGIN_FACTORY_WITH_JSON(QuickFilterFactory, "choqok_quickfilter.json", registerPlugin < QuickFilter > ();) QuickFilter::QuickFilter(QObject *parent, const QList< QVariant > &args) : Choqok::Plugin(QLatin1String("choqok_quickfilter"), parent) { Q_UNUSED(args); m_authorAction = new QAction(QIcon::fromTheme(QLatin1String("document-preview")), i18n("Filter by author"), this); m_authorAction->setCheckable(true); m_textAction = new QAction(QIcon::fromTheme(QLatin1String("document-preview")), i18n("Filter by content"), this); m_textAction->setCheckable(true); actionCollection()->addAction(QLatin1String("filterByAuthor"), m_authorAction); actionCollection()->addAction(QLatin1String("filterByContent"), m_textAction); setXMLFile(QLatin1String("quickfilterui.rc")); createUiInterface(); - connect(Choqok::UI::Global::mainWindow(), SIGNAL(currentMicroBlogWidgetChanged(Choqok::UI::MicroBlogWidget*)), this, SLOT(showAllPosts())); + connect(Choqok::UI::Global::mainWindow(), &Choqok::UI::MainWindow::currentMicroBlogWidgetChanged, + this, &QuickFilter::showAllPosts); } QuickFilter::~QuickFilter() { } void QuickFilter::filterByAuthor() { m_filterUser = m_aledit->text(); if (!m_filterUser.isEmpty() && Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()) { for (Choqok::UI::PostWidget *postwidget: Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()->postWidgets()) { if (!postwidget->currentPost()->author.userName.contains(m_filterUser, Qt::CaseInsensitive)) { postwidget->hide(); } else { postwidget->show(); } } - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - this, SLOT(filterNewPost(Choqok::UI::PostWidget*,Choqok::Account*,QString))); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &QuickFilter::filterNewPost); } else { showAllPosts(); } } void QuickFilter::filterByContent() { m_filterText = m_tledit->text(); if (!m_filterText.isEmpty() && Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()) { for (Choqok::UI::PostWidget *postwidget: Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()->postWidgets()) { if (!postwidget->currentPost()->content.contains(m_filterText, Qt::CaseInsensitive)) { postwidget->hide(); } else { postwidget->show(); } } - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - this, SLOT(filterNewPost(Choqok::UI::PostWidget*,Choqok::Account*,QString))); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &QuickFilter::filterNewPost); } else { showAllPosts(); } } void QuickFilter::createUiInterface() { m_authorToolbar = new QToolBar(i18n("Filter out timeline by author"), Choqok::UI::Global::mainWindow()); m_authorToolbar->setObjectName(QLatin1String("authorFilterToolbar")); m_textToolbar = new QToolBar(i18n("Filter out timeline by text"), Choqok::UI::Global::mainWindow()); m_textToolbar->setObjectName(QLatin1String("textFilterToolbar")); - connect(m_authorAction, SIGNAL(toggled(bool)), m_authorToolbar, SLOT(setVisible(bool))); - connect(m_textAction, SIGNAL(toggled(bool)), m_textToolbar, SLOT(setVisible(bool))); - connect(m_authorToolbar, SIGNAL(visibilityChanged(bool)), SLOT(showAuthorFilterUiInterface(bool))); - connect(m_textToolbar, SIGNAL(visibilityChanged(bool)), SLOT(showContentFilterUiInterface(bool))); + connect(m_authorAction, &QAction::toggled, m_authorToolbar, &QToolBar::setVisible); + connect(m_textAction, &QAction::toggled, m_textToolbar, &QToolBar::setVisible); + connect(m_authorToolbar, &QToolBar::visibilityChanged, this, &QuickFilter::showAuthorFilterUiInterface); + connect(m_textToolbar, &QToolBar::visibilityChanged, this, &QuickFilter::showContentFilterUiInterface); m_aledit = new QLineEdit(m_authorToolbar); m_aledit->setClearButtonEnabled(true); m_tledit = new QLineEdit(m_textToolbar); m_tledit->setClearButtonEnabled(true); QLabel *alabel = new QLabel(i18n("Author"), m_authorToolbar); QLabel *tlabel = new QLabel(i18n("Text"), m_textToolbar); m_authorToolbar->addWidget(alabel); m_authorToolbar->addWidget(m_aledit); QPushButton *authorCloseButton = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-close")), QString() , m_authorToolbar); authorCloseButton->setMaximumWidth(authorCloseButton->height()); - connect(authorCloseButton, SIGNAL(clicked(bool)), m_authorToolbar, SLOT(hide())); + connect(authorCloseButton, &QPushButton::clicked, m_authorToolbar, &QToolBar::hide); m_authorToolbar->addWidget(authorCloseButton); m_textToolbar->addWidget(tlabel); m_textToolbar->addWidget(m_tledit); QPushButton *textCloseButton = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-close")), QString() , m_textToolbar); textCloseButton->setMaximumWidth(textCloseButton->height()); - connect(textCloseButton, SIGNAL(clicked(bool)), m_textToolbar, SLOT(hide())); + connect(textCloseButton, &QPushButton::clicked, m_textToolbar, &QToolBar::hide); m_textToolbar->addWidget(textCloseButton); - connect(m_aledit, SIGNAL(editingFinished()), this , SLOT(filterByAuthor())); - connect(m_aledit, SIGNAL(textChanged(QString)), this, SLOT(updateUser(QString))); + connect(m_aledit, &QLineEdit::editingFinished, this, &QuickFilter::filterByAuthor); + connect(m_aledit, &QLineEdit::textChanged, this, &QuickFilter::updateUser); - connect(m_tledit, SIGNAL(editingFinished()), this, SLOT(filterByContent())); - connect(m_tledit, SIGNAL(textChanged(QString)), this, SLOT(updateContent(QString))); + connect(m_tledit, &QLineEdit::editingFinished, this, &QuickFilter::filterByContent); + connect(m_tledit, &QLineEdit::textChanged, this, &QuickFilter::updateContent); Choqok::UI::Global::mainWindow()->addToolBar(Qt::BottomToolBarArea, m_authorToolbar); Choqok::UI::Global::mainWindow()->addToolBar(Qt::BottomToolBarArea, m_textToolbar); m_authorToolbar->hide(); m_textToolbar->hide(); } void QuickFilter::showAuthorFilterUiInterface(bool show) { m_authorToolbar->setVisible(show); if (show) { m_textAction->setChecked(false); m_aledit->setFocus(); } else { m_aledit->clear(); m_authorAction->setChecked(false); } } void QuickFilter::showContentFilterUiInterface(bool show) { m_textToolbar->setVisible(show); if (show) { m_authorAction->setChecked(false); m_tledit->setFocus(); } else { m_tledit->clear(); m_textAction->setChecked(false); } } void QuickFilter::updateUser(QString user) { if (user.isEmpty()) { filterByAuthor(); } } void QuickFilter::updateContent(QString text) { if (text.isEmpty()) { filterByContent(); } } void QuickFilter::showAllPosts() { if (Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()) { for (Choqok::UI::PostWidget *postwidget: Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()->postWidgets()) { postwidget->show(); } m_aledit->clear(); m_tledit->clear(); disconnect(Choqok::UI::Global::SessionManager::self(), SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), this, SLOT(filterNewPost(Choqok::UI::PostWidget*,Choqok::Account*,QString))); } } void QuickFilter::filterNewPost(Choqok::UI::PostWidget *np, Choqok::Account *acc, QString timeline) { //qDebug()<currentMicroBlog()->currentAccount()->alias()<alias()<currentMicroBlog()->currentAccount() == acc && Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentTimeline()->timelineName() == timeline) { if (!m_aledit->text().isEmpty()) { if (!np->currentPost()->author.userName.contains(m_aledit->text())) { np->hide(); } else { np->show(); } } if (!m_tledit->text().isEmpty()) { if (!np->currentPost()->content.contains(m_tledit->text())) { np->hide(); } else { np->show(); } } } } #include "quickfilter.moc" diff --git a/plugins/searchaction/searchaction.cpp b/plugins/searchaction/searchaction.cpp index a42439de..c4836166 100644 --- a/plugins/searchaction/searchaction.cpp +++ b/plugins/searchaction/searchaction.cpp @@ -1,69 +1,69 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "searchaction.h" #include #include #include #include #include #include "choqokuiglobal.h" #include "microblogwidget.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" K_PLUGIN_FACTORY_WITH_JSON(SearchActionFactory, "choqok_searchaction.json", registerPlugin < SearchAction > ();) SearchAction::SearchAction(QObject *parent, const QList< QVariant > &) : Plugin(QLatin1String("choqok_searchaction"), parent) { QAction *action = new QAction(QIcon::fromTheme(QLatin1String("edit-find")), i18n("Search..."), this); action->setShortcut(QKeySequence(Qt::ControlModifier | Qt::Key_F)); actionCollection()->addAction(QLatin1String("search"), action); - connect(action, SIGNAL(triggered(bool)), SLOT(slotSearch())); + connect(action, &QAction::triggered, this, &SearchAction::slotSearch); setXMLFile(QLatin1String("searchactionui.rc")); } SearchAction::~SearchAction() { } void SearchAction::slotSearch() { TwitterApiAccount *curAccount = qobject_cast(Choqok::UI::Global::mainWindow()->currentMicroBlog()->currentAccount()); if (curAccount) { TwitterApiMicroBlog *mBlog = qobject_cast(curAccount->microblog()); mBlog->showSearchDialog(curAccount); } else { KMessageBox::sorry(Choqok::UI::Global::mainWindow(), i18n("The Search action plugin does not support the current microblog.")); } } #include "searchaction.moc" diff --git a/plugins/shorteners/bit_ly/bit_ly_config.cpp b/plugins/shorteners/bit_ly/bit_ly_config.cpp index 4b8babcc..2efb911e 100644 --- a/plugins/shorteners/bit_ly/bit_ly_config.cpp +++ b/plugins/shorteners/bit_ly/bit_ly_config.cpp @@ -1,146 +1,150 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "bit_ly_config.h" +#include +#include +#include #include #include #include #include #include #include #include #include "notifymanager.h" #include "passwordmanager.h" #include "bit_ly_settings.h" K_PLUGIN_FACTORY_WITH_JSON(Bit_ly_ConfigFactory, "choqok_bit_ly_config.json", registerPlugin < Bit_ly_Config > ();) Bit_ly_Config::Bit_ly_Config(QWidget *parent, const QVariantList &): KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_bit_ly")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mBitLYCtl")); wd->setMinimumWidth(400); ui.setupUi(wd); addConfig(Bit_ly_Settings::self(), wd); layout->addWidget(wd); QRegExp rx(QLatin1String("([a-z0-9_]){4,32}"), Qt::CaseInsensitive); QValidator *val0 = new QRegExpValidator(rx, 0); ui.kcfg_login->setValidator(val0); rx.setPattern(QLatin1String("([a-z0-9_]){1,40}")); QValidator *val1 = new QRegExpValidator(rx, 0); ui.kcfg_api_key->setValidator(val1); ui.help_label->setTextFormat(Qt::RichText); ui.help_label->setText(i18nc("The your_api_key part of the URL is a fixed part of the URL " "and should probably not be changed in localization.", "You can find your API key here")); domains << QLatin1String("bit.ly") << QLatin1String("j.mp"); ui.kcfg_domain->addItems(domains); - connect(ui.kcfg_login, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.kcfg_api_key, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.kcfg_domain, SIGNAL(currentIndexChanged(int)), SLOT(emitChanged())); - connect(ui.validate_button, SIGNAL(clicked(bool)), SLOT(slotValidate())); + connect(ui.kcfg_login, &QLineEdit::textChanged, this, &Bit_ly_Config::emitChanged); + connect(ui.kcfg_api_key, &QLineEdit::textChanged, this, &Bit_ly_Config::emitChanged); + connect(ui.kcfg_domain, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &Bit_ly_Config::emitChanged); + connect(ui.validate_button, &QPushButton::clicked, this, &Bit_ly_Config::slotValidate); } Bit_ly_Config::~Bit_ly_Config() { } void Bit_ly_Config::load() { KCModule::load(); KConfigGroup grp(KSharedConfig::openConfig(), "Bit.ly Shortener"); ui.kcfg_login->setText(grp.readEntry("login", "")); ui.kcfg_domain->setCurrentIndex(domains.indexOf(grp.readEntry("domain", "bit.ly"))); ui.kcfg_api_key->setText(Choqok::PasswordManager::self()->readPassword(QStringLiteral("bitly_%1") .arg(ui.kcfg_login->text()))); } void Bit_ly_Config::save() { KCModule::save(); KConfigGroup grp(KSharedConfig::openConfig(), "Bit.ly Shortener"); grp.writeEntry("login", ui.kcfg_login->text()); grp.writeEntry("domain", domains.at(ui.kcfg_domain->currentIndex())); Choqok::PasswordManager::self()->writePassword(QStringLiteral("bitly_%1").arg(ui.kcfg_login->text()), ui.kcfg_api_key->text()); } void Bit_ly_Config::emitChanged() { Q_EMIT changed(true); } void Bit_ly_Config::slotValidate() { ui.validate_button->setEnabled(false); ui.validate_button->setText(i18n("Checking...")); QString login = QCoreApplication::applicationName(); QString apiKey = QLatin1String("R_bdd1ae8b6191dd36e13fc77ca1d4f27f"); QUrl reqUrl(QLatin1String("http://api.bit.ly/v3/validate")); QUrlQuery reqQuery; reqQuery.addQueryItem(QLatin1String("x_login"), ui.kcfg_login->text()); reqQuery.addQueryItem(QLatin1String("x_apiKey"), ui.kcfg_api_key->text()); if (Bit_ly_Settings::domain() == QLatin1String("j.mp")) { //bit.ly is default domain reqQuery.addQueryItem(QLatin1String("domain"), QLatin1String("j.mp")); } reqQuery.addQueryItem(QLatin1String("login"), QLatin1String(login.toUtf8())); reqQuery.addQueryItem(QLatin1String("apiKey"), QLatin1String(apiKey.toUtf8())); reqQuery.addQueryItem(QLatin1String("format"), QLatin1String("txt")); reqUrl.setQuery(reqQuery); KIO::StoredTransferJob *job = KIO::storedGet(reqUrl, KIO::Reload, KIO::HideProgressInfo); job->exec(); if (!job->error()) { QString output(QLatin1String(job->data())); if (output.startsWith(QLatin1Char('0'))) KMessageBox::error(this, i18nc("The your_api_key part of the URL is a fixed part of the URL " "and should probably not be changed in localization.", "Provided data is invalid. Try another login or API key.\n" "You can find it on http://bit.ly/a/your_api_key")); if (output.startsWith(QLatin1Char('1'))) { KMessageBox::information(this, i18n("You entered valid information.")); } } else { Choqok::NotifyManager::error(job->errorString(), i18n("bit.ly Config Error")); } ui.validate_button->setEnabled(true); ui.validate_button->setText(i18n("Validate")); } #include "bit_ly_config.moc" diff --git a/plugins/shorteners/is_gd/is_gd.cpp b/plugins/shorteners/is_gd/is_gd.cpp index 17e0e181..152bb725 100644 --- a/plugins/shorteners/is_gd/is_gd.cpp +++ b/plugins/shorteners/is_gd/is_gd.cpp @@ -1,89 +1,89 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2009-2010 Felix Rohrbach This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "is_gd.h" #include #include #include #include #include #include "notifymanager.h" #include "is_gd_settings.h" K_PLUGIN_FACTORY_WITH_JSON(Is_gdFactory, "choqok_is_gd.json", registerPlugin < Is_gd > ();) Is_gd::Is_gd(QObject *parent, const QVariantList &) : Choqok::Shortener(QLatin1String("choqok_is_gd"), parent) { } Is_gd::~Is_gd() { } QString Is_gd::shorten(const QString &url) { Is_gd_Settings::self()->load(); QUrl reqUrl(QLatin1String("https://is.gd/create.php")); QUrlQuery reqQuery; reqQuery.addQueryItem(QLatin1String("format"), QLatin1String("json")); reqQuery.addQueryItem(QLatin1String("url"), QUrl(url).url()); if (Is_gd_Settings::logstats()) { reqQuery.addQueryItem(QLatin1String("logstats"), QLatin1String("true")); } reqUrl.setQuery(reqQuery); QEventLoop loop; KIO::StoredTransferJob *job = KIO::storedGet(reqUrl, KIO::Reload, KIO::HideProgressInfo); - connect(job, SIGNAL(result(KJob*)), &loop, SLOT(quit())); + connect(job, &KIO::StoredTransferJob::result, &loop, &QEventLoop::quit); job->start(); loop.exec(); if (job->error() == KJob::NoError) { const QJsonDocument json = QJsonDocument::fromJson(job->data()); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); if (!map[ QLatin1String("errorcode") ].toString().isEmpty()) { Choqok::NotifyManager::error(map[ QLatin1String("errormessage") ].toString(), i18n("is.gd Error")); return url; } QString shorturl = map[ QLatin1String("shorturl") ].toString(); if (!shorturl.isEmpty()) { return shorturl; } } else { Choqok::NotifyManager::error(i18n("Malformed response"), i18n("is.gd Error")); } } else { Choqok::NotifyManager::error(i18n("Cannot create a short URL.\n%1", job->errorString()), i18n("is.gd Error")); } return url; } #include "is_gd.moc" diff --git a/plugins/shorteners/tighturl/tighturl.cpp b/plugins/shorteners/tighturl/tighturl.cpp index de97774a..9e2012ab 100644 --- a/plugins/shorteners/tighturl/tighturl.cpp +++ b/plugins/shorteners/tighturl/tighturl.cpp @@ -1,79 +1,79 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "tighturl.h" #include #include #include #include #include #include "notifymanager.h" K_PLUGIN_FACTORY_WITH_JSON(TightUrlFactory, "choqok_tighturl.json", registerPlugin < TightUrl > ();) TightUrl::TightUrl(QObject *parent, const QVariantList &) : Choqok::Shortener(QLatin1String("choqok_tighturl"), parent) { } QString TightUrl::shorten(const QString &url) { QUrl reqUrl(QLatin1String("http://2tu.us/")); QUrlQuery reqQuery; reqQuery.addQueryItem(QLatin1String("save"), QLatin1String("y")); reqQuery.addQueryItem(QLatin1String("url"), QUrl(url).url()); reqUrl.setQuery(reqQuery); QEventLoop loop; KIO::StoredTransferJob *job = KIO::storedGet(reqUrl, KIO::Reload, KIO::HideProgressInfo); - connect(job, SIGNAL(result(KJob*)), &loop, SLOT(quit())); + connect(job, &KIO::StoredTransferJob::result, &loop, &QEventLoop::quit); job->start(); loop.exec(); if (job->error() == KJob::NoError) { QString output(QLatin1String(job->data())); QRegExp rx(QLatin1String("(.+)")); rx.setMinimal(true); rx.indexIn(output); output = rx.cap(1); rx.setPattern(QLatin1String("href=[\'\"](.+)[\'\"]")); rx.indexIn(output); output = rx.cap(1); if (!output.isEmpty()) { return output; } } else { Choqok::NotifyManager::error(i18n("Cannot create a short URL.\n%1", job->errorString()), i18n("TightUrl Error")); } return url; } TightUrl::~TightUrl() { } #include "tighturl.moc" diff --git a/plugins/shorteners/tinyarro_ws/tinyarro_ws_config.cpp b/plugins/shorteners/tinyarro_ws/tinyarro_ws_config.cpp index 75508e23..72283700 100644 --- a/plugins/shorteners/tinyarro_ws/tinyarro_ws_config.cpp +++ b/plugins/shorteners/tinyarro_ws/tinyarro_ws_config.cpp @@ -1,96 +1,98 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "tinyarro_ws_config.h" +#include #include #include #include #include #include #include "passwordmanager.h" #include "tinyarro_ws_settings.h" K_PLUGIN_FACTORY_WITH_JSON(Tinyarro_ws_ConfigFactory, "choqok_tinyarro_ws_config.json", registerPlugin < Tinyarro_ws_Config > ();) Tinyarro_ws_Config::Tinyarro_ws_Config(QWidget *parent, const QVariantList &): KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_tinyarro_ws")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mTinyarro_ws_Ctl")); ui.setupUi(wd); addConfig(Tinyarro_ws_Settings::self(), wd); layout->addWidget(wd); QString domain = QLatin1String(".ws"); hostList.insert(QChar(0x27A8) + domain, QLatin1String("xn--ogi.ws")); hostList.insert(QChar(0x27AF) + domain, QLatin1String("xn--vgi.ws")); hostList.insert(QChar(0x2794) + domain, QLatin1String("xn--3fi.ws")); hostList.insert(QChar(0x279E) + domain, QLatin1String("xn--egi.ws")); hostList.insert(QChar(0x27BD) + domain, QLatin1String("xn--9gi.ws")); hostList.insert(QChar(0x27B9) + domain, QLatin1String("xn--5gi.ws")); hostList.insert(QChar(0x2729) + domain, QLatin1String("xn--1ci.ws")); hostList.insert(QChar(0x273F) + domain, QLatin1String("xn--odi.ws")); hostList.insert(QChar(0x2765) + domain, QLatin1String("xn--rei.ws")); hostList.insert(QChar(0x203A) + domain, QLatin1String("xn--cwg.ws")); hostList.insert(QChar(0x2318) + domain, QLatin1String("xn--bih.ws")); hostList.insert(QChar(0x203D) + domain, QLatin1String("xn--fwg.ws")); hostList.insert(QChar(0x2601) + domain, QLatin1String("xn--l3h.ws")); hostList.insert(QLatin1String("ta.gd"), QLatin1String("ta.gd")); hostList.insert(i18n("Random host"), QLatin1String("Random")); for (const QString &host: hostList.keys()) { ui.kcfg_tinyarro_ws_host->addItem(host); } - connect(ui.kcfg_tinyarro_ws_host, SIGNAL(currentIndexChanged(int)), SLOT(emitChanged())); + connect(ui.kcfg_tinyarro_ws_host, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &Tinyarro_ws_Config::emitChanged); } Tinyarro_ws_Config::~Tinyarro_ws_Config() { } void Tinyarro_ws_Config::load() { KCModule::load(); KConfigGroup grp(KSharedConfig::openConfig(), "Tinyarro.ws Shortener"); ui.kcfg_tinyarro_ws_host->setCurrentIndex(grp.readEntry("tinyarro_ws_host", "0").toInt()); } void Tinyarro_ws_Config::save() { KCModule::save(); KConfigGroup grp(KSharedConfig::openConfig(), "Tinyarro.ws Shortener"); grp.writeEntry("tinyarro_ws_host", ui.kcfg_tinyarro_ws_host->currentIndex()); grp.writeEntry("tinyarro_ws_host_punny", hostList[ui.kcfg_tinyarro_ws_host->currentText()]); } void Tinyarro_ws_Config::emitChanged() { Q_EMIT changed(true); } #include "tinyarro_ws_config.moc" diff --git a/plugins/shorteners/ur1_ca/ur1_ca.cpp b/plugins/shorteners/ur1_ca/ur1_ca.cpp index 63fdd907..a1e2e7fc 100644 --- a/plugins/shorteners/ur1_ca/ur1_ca.cpp +++ b/plugins/shorteners/ur1_ca/ur1_ca.cpp @@ -1,79 +1,79 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "ur1_ca.h" #include #include #include #include #include #include "notifymanager.h" K_PLUGIN_FACTORY_WITH_JSON(Ur1_caFactory, "choqok_ur1_ca.json", registerPlugin < Ur1_ca> ();) Ur1_ca::Ur1_ca(QObject *parent, const QVariantList &) : Choqok::Shortener(QLatin1String("choqok_ur1_ca"), parent) { } Ur1_ca::~Ur1_ca() { } QString Ur1_ca::shorten(const QString &url) { QUrl reqUrl(QLatin1String("http://ur1.ca/")); QString temp; temp = QLatin1String(QUrl::toPercentEncoding(url)); QByteArray parg("longurl="); parg.append(temp.toLatin1()); QEventLoop loop; KIO::StoredTransferJob *job = KIO::storedHttpPost(parg, reqUrl, KIO::HideProgressInfo); job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: application/x-www-form-urlencoded")); - connect(job, SIGNAL(result(KJob*)), &loop, SLOT(quit())); + connect(job, &KIO::StoredTransferJob::result, &loop, &QEventLoop::quit); job->start(); loop.exec(); if (job->error() == KJob::NoError) { QString output(QLatin1String(job->data())); QRegExp rx(QLatin1String("

(.*)

")); rx.setMinimal(true); rx.indexIn(output); output = rx.cap(1); rx.setPattern(QLatin1String("href=[\'\"](.*)[\'\"]")); rx.indexIn(output); output = rx.cap(1); if (!output.isEmpty()) { return output; } } else { Choqok::NotifyManager::error(i18n("Cannot create a short URL.\n%1", job->errorString()), i18n("ur1.ca Error")); } return url; } -#include "ur1_ca.moc" \ No newline at end of file +#include "ur1_ca.moc" diff --git a/plugins/shorteners/yourls/yourls.cpp b/plugins/shorteners/yourls/yourls.cpp index 9af33b64..64c96e2b 100644 --- a/plugins/shorteners/yourls/yourls.cpp +++ b/plugins/shorteners/yourls/yourls.cpp @@ -1,101 +1,101 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2011 Marcello Ceschia Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "yourls.h" #include #include #include #include #include "notifymanager.h" #include "passwordmanager.h" #include "yourlssettings.h" K_PLUGIN_FACTORY_WITH_JSON(YourlsFactory, "choqok_yourls.json", registerPlugin < Yourls > ();) Yourls::Yourls(QObject *parent, const QVariantList &) : Choqok::Shortener(QLatin1String("choqok_yourls"), parent) { - connect(YourlsSettings::self(), SIGNAL(configChanged()), - SLOT(reloadConfigs())); + connect(YourlsSettings::self(), &YourlsSettings::configChanged, + this, &Yourls::reloadConfigs); } Yourls::~Yourls() {} QString Yourls::shorten(const QString &url) { QUrl reqUrl(YourlsSettings::yourlsHost()); QUrlQuery reqQuery; reqQuery.addQueryItem(QLatin1String("action"), QLatin1String("shorturl")); /* set action to shorturl */ reqQuery.addQueryItem(QLatin1String("format"), QLatin1String("xml")); /* get result as xml */ reqQuery.addQueryItem(QLatin1String("url"), QUrl(url).url()); /* url to be shorted */ password = QLatin1String(Choqok::PasswordManager::self()->readPassword( QStringLiteral("yourls_%1").arg(YourlsSettings::username())).toUtf8()); if (!YourlsSettings::username().isEmpty()) { reqQuery.addQueryItem(QLatin1String("username"), YourlsSettings::username()); reqQuery.addQueryItem(QLatin1String("password"), password); } reqUrl.setQuery(reqQuery); KIO::StoredTransferJob *job = KIO::storedGet(reqUrl, KIO::Reload, KIO::HideProgressInfo); job->exec(); if (!job->error()) { const QByteArray data = job->data(); /* output field */ QString output = QLatin1String(data); QRegExp rx(QLatin1String("(.+)")); rx.setMinimal(true); rx.indexIn(output); output = rx.cap(1); if (!output.isEmpty()) { return output; } else { output = QLatin1String(data); QRegExp rx(QLatin1String("(.+)")); rx.setMinimal(true); rx.indexIn(output); output = rx.cap(1); Choqok::NotifyManager::error(output, i18n("Yourls Error")); } } else { Choqok::NotifyManager::error(i18n("Cannot create a short URL.\n%1", job->errorString())); } return url; } void Yourls::reloadConfigs() { password = QLatin1String(Choqok::PasswordManager::self()->readPassword( QStringLiteral("yourls_%1").arg(YourlsSettings::username())).toUtf8()); } #include "yourls.moc" diff --git a/plugins/shorteners/yourls/yourlsconfig.cpp b/plugins/shorteners/yourls/yourlsconfig.cpp index c1ae42c6..0e097c02 100644 --- a/plugins/shorteners/yourls/yourlsconfig.cpp +++ b/plugins/shorteners/yourls/yourlsconfig.cpp @@ -1,77 +1,78 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "yourlsconfig.h" +#include #include #include #include #include "passwordmanager.h" #include "yourlssettings.h" K_PLUGIN_FACTORY_WITH_JSON(YourlsConfigFactory, "choqok_yourls_config.json", registerPlugin < YourlsConfig > ();) YourlsConfig::YourlsConfig(QWidget *parent, const QVariantList &): KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_yourls")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mYourlsCtl")); ui.setupUi(wd); addConfig(YourlsSettings::self(), wd); layout->addWidget(wd); - connect(ui.kcfg_username, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.cfg_password, SIGNAL(textChanged(QString)), SLOT(emitChanged())); + connect(ui.kcfg_username, &QLineEdit::textChanged, this, &YourlsConfig::emitChanged); + connect(ui.cfg_password, &QLineEdit::textChanged, this, &YourlsConfig::emitChanged); } YourlsConfig::~YourlsConfig() { } void YourlsConfig::load() { KCModule::load(); ui.cfg_password->setText(Choqok::PasswordManager::self()->readPassword(QStringLiteral("yourls_%1") .arg(ui.kcfg_username->text()))); } void YourlsConfig::save() { KCModule::save(); Choqok::PasswordManager::self()->writePassword(QStringLiteral("yourls_%1").arg(ui.kcfg_username->text()), ui.cfg_password->text()); } void YourlsConfig::emitChanged() { Q_EMIT changed(true); - disconnect(ui.kcfg_username, SIGNAL(textChanged(QString)), this, SLOT(emitChanged())); - disconnect(ui.cfg_password, SIGNAL(textChanged(QString)), this, SLOT(emitChanged())); + disconnect(ui.kcfg_username, &QLineEdit::textChanged, this, &YourlsConfig::emitChanged); + disconnect(ui.cfg_password, &QLineEdit::textChanged, this, &YourlsConfig::emitChanged); } #include "yourlsconfig.moc" diff --git a/plugins/untiny/untiny.cpp b/plugins/untiny/untiny.cpp index 7cd327e8..6eefedbe 100644 --- a/plugins/untiny/untiny.cpp +++ b/plugins/untiny/untiny.cpp @@ -1,128 +1,126 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "untiny.h" #include #include #include #include "choqokuiglobal.h" #include "postwidget.h" #include "shortenmanager.h" #include "untinysettings.h" K_PLUGIN_FACTORY_WITH_JSON(UnTinyFactory, "choqok_untiny.json", registerPlugin < UnTiny > ();) UnTiny::UnTiny(QObject* parent, const QList< QVariant >& ) : Choqok::Plugin(QLatin1String("choqok_untiny"), parent) , state(Stopped) { - connect( Choqok::UI::Global::SessionManager::self(), - &Choqok::UI::Global::SessionManager::newPostWidgetAdded, - this, - &UnTiny::slotAddNewPostWidget ); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &UnTiny::slotAddNewPostWidget); } UnTiny::~UnTiny() { } void UnTiny::slotAddNewPostWidget(Choqok::UI::PostWidget* newWidget) { postsQueue.enqueue(newWidget); if(state == Stopped){ state = Running; QTimer::singleShot(1000, this, SLOT(startParsing())); } } void UnTiny::startParsing() { int i = 8; while( !postsQueue.isEmpty() && i>0 ){ parse(postsQueue.dequeue()); --i; } if(postsQueue.isEmpty()) state = Stopped; else QTimer::singleShot(500, this, SLOT(startParsing())); } void UnTiny::parse(QPointer postToParse) { if(!postToParse) return; QStringList redirectList, pureList = postToParse->urls(); QString content = postToParse->currentPost()->content; for (int i=0; i < pureList.count(); ++i) { if(pureList[i].length() > 30){ continue; } if(!pureList[i].startsWith(QLatin1String("http"), Qt::CaseInsensitive)){ pureList[i].prepend(QLatin1String("http://")); } redirectList << pureList[i]; } for (const QString &url: redirectList) { KIO::MimetypeJob *job = KIO::mimetype( QUrl::fromUserInput(url), KIO::HideProgressInfo ); if ( !job ) { qCritical() << "Cannot create a http header request!"; break; } connect( job, &KIO::MimetypeJob::permanentRedirection, this, &UnTiny::slot301Redirected ); mParsingList.insert(job, postToParse); job->start(); } } void UnTiny::slot301Redirected(KIO::Job* job, QUrl fromUrl, QUrl toUrl) { QPointer postToParse = mParsingList.take(job); job->kill(); if(postToParse){ QString content = postToParse->content(); QString fromUrlStr = fromUrl.url(); content.replace(QRegExp(QStringLiteral("title='%1\'").arg(fromUrlStr)), QStringLiteral("title='%1\'").arg(toUrl.url())); content.replace(QRegExp(QStringLiteral("href='%1\'").arg(fromUrlStr)), QStringLiteral("href='%1\'").arg(toUrl.url())); postToParse->setContent(content); Choqok::ShortenManager::self()->emitNewUnshortenedUrl(postToParse, fromUrl, toUrl); if (toUrl.url().length() < 30 && fromUrl.host() == QLatin1String("t.co")){ KIO::TransferJob *job = KIO::mimetype( toUrl, KIO::HideProgressInfo ); if ( job ) { connect( job, &KIO::MimetypeJob::permanentRedirection, this, &UnTiny::slot301Redirected ); mParsingList.insert(job, postToParse); job->start(); } } } } #include "untiny.moc" diff --git a/plugins/uploaders/flickr/flickr.cpp b/plugins/uploaders/flickr/flickr.cpp index 22d93ad8..b055830e 100644 --- a/plugins/uploaders/flickr/flickr.cpp +++ b/plugins/uploaders/flickr/flickr.cpp @@ -1,240 +1,239 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "flickr.h" #include #include #include #include #include #include #include "mediamanager.h" #include "passwordmanager.h" #include "flickrsettings.h" const static QString apiKey = QLatin1String("13f602e6e705834d8cdd5dd2ccb19651"); const static QString apiSecret = QLatin1String("98c89dbe39ae3bea"); const static QString apiKeSec = apiSecret + QLatin1String("api_key") + apiKey; K_PLUGIN_FACTORY_WITH_JSON(FlickrFactory, "choqok_flickr.json", registerPlugin < Flickr > ();) Flickr::Flickr(QObject *parent, const QList &) : Choqok::Uploader(QLatin1String("choqok_flickr"), parent) { } Flickr::~Flickr() { } void Flickr::upload(const QUrl &localUrl, const QByteArray &medium, const QByteArray &mediumType) { QUrl url(QLatin1String("https://api.flickr.com/services/upload/")); FlickrSettings::self()->load(); QString token = Choqok::PasswordManager::self()->readPassword(QStringLiteral("flickr_%1") .arg(FlickrSettings::username())); QMap formdata; formdata[QLatin1String("api_key")] = apiKey.toUtf8(); formdata[QLatin1String("auth_token")] = token.toUtf8(); QString preSign; if (FlickrSettings::hidefromsearch()) { formdata[QLatin1String("hidden")] = QByteArray("2"); preSign.append(QLatin1String("hidden2")); } else { formdata[QLatin1String("hidden")] = QByteArray("1"); preSign.append(QLatin1String("hidden1")); } if (FlickrSettings::forprivate()) { if (FlickrSettings::forfamily()) { formdata[QLatin1String("is_family")] = QByteArray("1"); preSign.append(QLatin1String("is_family1")); } if (FlickrSettings::forfriends()) { formdata[QLatin1String("is_friend")] = QByteArray("1"); preSign.append(QLatin1String("is_friend1")); } formdata[QLatin1String("is_public")] = QByteArray("0"); preSign.append(QLatin1String("is_public0")); } else if (FlickrSettings::forpublic()) { formdata[QLatin1String("is_public")] = QByteArray("1"); preSign.append(QLatin1String("is_public1")); } if (FlickrSettings::safe()) { formdata[QLatin1String("safety_level")] = QByteArray("1"); preSign.append(QLatin1String("safety_level1")); } if (FlickrSettings::moderate()) { formdata[QLatin1String("safety_level")] = QByteArray("2"); preSign.append(QLatin1String("safety_level2")); } if (FlickrSettings::restricted()) { formdata[QLatin1String("safety_level")] = QByteArray("3"); preSign.append(QLatin1String("safety_level3")); } formdata[QLatin1String("api_sig")] = createSign("auth_token" + token.toUtf8() + preSign.toUtf8()); QMap mediafile; mediafile[QLatin1String("name")] = "photo"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCritical() << "Cannot create a http POST request!"; return; } job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: multipart/form-data; boundary=AaB03x")); mUrlMap[job] = localUrl; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotUpload(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &Flickr::slotUpload); job->start(); } void Flickr::slotUpload(KJob *job) { QUrl localUrl = mUrlMap.take(job); if (job->error()) { qCritical() << "Job Error:" << job->errorString(); Q_EMIT uploadingFailed(localUrl, job->errorString()); return; } else { QDomDocument rep; QByteArray buffer = qobject_cast(job)->data(); //qDebug() << buffer; rep.setContent(buffer); QString photoId; QDomElement element = rep.documentElement(); if (element.tagName() == QLatin1String("rsp")) { QString res; res = element.attribute(QLatin1String("stat") , QLatin1String("fail")); QDomNode node = element.firstChild(); while (!node.isNull()) { QDomElement elem = node.toElement(); if (res == QLatin1String("ok")) { if (elem.tagName() == QLatin1String("photoid")) { photoId = elem.text(); } QString remUrl; if (FlickrSettings::shorturl()) { remUrl = QLatin1String("https://flic.kr/p/") + base58encode(photoId.toULongLong()); } else { remUrl = QLatin1String("https://flickr.com/photos/") + FlickrSettings::nsid() + QLatin1Char('/') + photoId; } Q_EMIT mediumUploaded(localUrl, remUrl); return; } else if (res == QLatin1String("fail")) { QString errMsg; if (elem.tagName() == QLatin1String("err")) { errMsg = elem.text(); int errCode = elem.attribute(QLatin1String("code") , QLatin1String("0")).toInt(); switch (errCode) { case 2: errMsg = i18n("The photo required argument was missing"); break; case 3: errMsg = i18n("The file was not correctly uploaded"); break; case 4: errMsg = i18n("The file was zero bytes in length"); break; case 5: errMsg = i18n("Filetype was not recognised"); break; case 6: errMsg = i18n("The calling user has reached their monthly bandwidth limit"); break; case 96: case 97: errMsg = i18n("Signature problem. Please try again later"); break; case 98: case 99: /*TODO: Show auth dialog */ errMsg = i18n("Login failed. Please re-authenticate Choqok"); break; case 105: errMsg = i18n("The requested service is temporarily unavailable. Try again later"); break; default: errMsg = i18n("Unknown Error:%1. Please try again later", errCode); break; } Q_EMIT uploadingFailed(localUrl, errMsg); return; } } else { Q_EMIT uploadingFailed(localUrl, i18n("Malformed response")); return; } node = node.nextSibling(); } } else { Q_EMIT uploadingFailed(localUrl, i18n("Malformed response")); return; } } } QString Flickr::base58encode(quint64 num) { QString alphabet = QLatin1String("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"); uint baseCount = alphabet.count(); QString encoded; while (num >= baseCount) { encoded.prepend(alphabet.at(int(num % baseCount))); num /= baseCount; } if (num) { encoded.prepend(alphabet.at(int(num))); } return encoded; } QByteArray Flickr::createSign(QByteArray req) { return QCryptographicHash::hash(apiKeSec.toUtf8().append(req), QCryptographicHash::Md5).toHex(); } #include "flickr.moc" diff --git a/plugins/uploaders/flickr/flickrconfig.cpp b/plugins/uploaders/flickr/flickrconfig.cpp index d0c01cfe..ff520c91 100644 --- a/plugins/uploaders/flickr/flickrconfig.cpp +++ b/plugins/uploaders/flickr/flickrconfig.cpp @@ -1,314 +1,316 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "flickrconfig.h" +#include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include "choqoktools.h" #include "passwordmanager.h" #include "flickrsettings.h" K_PLUGIN_FACTORY_WITH_JSON(FlickrConfigFactory, "choqok_flickr_config.json", registerPlugin < FlickrConfig > ();) const QString apiKey = QLatin1String("13f602e6e705834d8cdd5dd2ccb19651"); const QString apiSecret = QLatin1String("98c89dbe39ae3bea"); const QString apiKeSec = apiSecret + QLatin1String("api_key") + apiKey; FlickrConfig::FlickrConfig(QWidget *parent, const QVariantList &) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_flickr")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mFlickrCtl")); ui.setupUi(wd); addConfig(FlickrSettings::self(), wd); layout->addWidget(wd); - connect(ui.authButton, SIGNAL(clicked()), SLOT(slotAuthButton_clicked())); - connect(ui.cfg_shorturl, SIGNAL(stateChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_forprivate, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_forfriends, SIGNAL(stateChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_forfamily, SIGNAL(stateChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_forpublic, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_safe, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_moderate, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_restricted, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_hidefromsearch, SIGNAL(stateChanged(int)), SLOT(emitChanged())); + connect(ui.authButton, &QPushButton::clicked, this, &FlickrConfig::slotAuthButton_clicked); + connect(ui.cfg_shorturl, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged); + connect(ui.cfg_forprivate, &QRadioButton::clicked, this, &FlickrConfig::emitChanged); + connect(ui.cfg_forfriends, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged); + connect(ui.cfg_forfamily, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged); + connect(ui.cfg_forpublic, &QRadioButton::clicked, this, &FlickrConfig::emitChanged); + connect(ui.cfg_safe, &QRadioButton::clicked, this, &FlickrConfig::emitChanged); + connect(ui.cfg_moderate, &QRadioButton::clicked, this, &FlickrConfig::emitChanged); + connect(ui.cfg_restricted, &QRadioButton::clicked, this, &FlickrConfig::emitChanged); + connect(ui.cfg_hidefromsearch, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged); } FlickrConfig::~FlickrConfig() { } void FlickrConfig::load() { KCModule::load(); KConfigGroup grp(KSharedConfig::openConfig(), "Flickr Uploader"); m_nsid = grp.readEntry("nsid", ""); m_username = grp.readEntry("username", ""); m_fullname = grp.readEntry("fullname", ""); ui.cfg_shorturl->setChecked(grp.readEntry("shorturl", true)); ui.cfg_forprivate->setChecked(grp.readEntry("forprivate", false)); ui.cfg_forfriends->setChecked(grp.readEntry("forfriends", false)); ui.cfg_forfamily->setChecked(grp.readEntry("forfamily", false)); ui.cfg_forpublic->setChecked(grp.readEntry("forpublic", true)); ui.cfg_safe->setChecked(grp.readEntry("safe", true)); ui.cfg_moderate->setChecked(grp.readEntry("moderate", false)); ui.cfg_restricted->setChecked(grp.readEntry("restricted", false)); ui.cfg_hidefromsearch->setChecked(grp.readEntry("hidefromsearch", false)); m_token = Choqok::PasswordManager::self()->readPassword(QStringLiteral("flickr_%1") .arg(m_username)); setAuthenticated(!m_token.isEmpty()); } void FlickrConfig::save() { KCModule::save(); KConfigGroup grp(KSharedConfig::openConfig(), "Flickr Uploader"); grp.writeEntry("nsid", m_nsid); grp.writeEntry("username", m_username); grp.writeEntry("fullname", m_fullname); grp.writeEntry("shorturl", ui.cfg_shorturl->isChecked()); grp.writeEntry("forprivate", ui.cfg_forprivate->isChecked()); grp.writeEntry("forfriends", ui.cfg_forfriends->isChecked()); grp.writeEntry("forfamily", ui.cfg_forfamily->isChecked()); grp.writeEntry("forpublic", ui.cfg_forpublic->isChecked()); grp.writeEntry("safe", ui.cfg_safe->isChecked()); grp.writeEntry("moderate", ui.cfg_moderate->isChecked()); grp.writeEntry("restricted", ui.cfg_restricted->isChecked()); grp.writeEntry("hidefromsearch", ui.cfg_hidefromsearch->isChecked()); Choqok::PasswordManager::self()->writePassword(QStringLiteral("flickr_%1").arg(m_username), m_token); } void FlickrConfig::emitChanged() { ui.cfg_forfamily->setEnabled(ui.cfg_forprivate->isChecked()); ui.cfg_forfriends->setEnabled(ui.cfg_forprivate->isChecked()); Q_EMIT changed(true); } void FlickrConfig::getFrob() { m_frob.clear(); QUrl url(QLatin1String("https://flickr.com/services/rest/")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("method"), QLatin1String("flickr.auth.getFrob")); urlQuery.addQueryItem(QLatin1String("api_key"), QLatin1String(apiKey.toUtf8())); urlQuery.addQueryItem(QLatin1String("api_sig"), QLatin1String(createSign("methodflickr.auth.getFrob"))); url.setQuery(urlQuery); QString errMsg; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); job->exec(); if (!job->error()) { QDomDocument rep; rep.setContent(job->data()); QDomElement element = rep.documentElement(); if (element.tagName() == QLatin1String("rsp")) { QString res; res = element.attribute(QLatin1String("stat") , QLatin1String("fail")); QDomNode node = element.firstChild(); while (!node.isNull()) { QDomElement elem = node.toElement(); if (res == QLatin1String("ok")) { if (elem.tagName() == QLatin1String("frob")) { m_frob = elem.text(); } return; } else if (res == QLatin1String("fail")) { if (elem.tagName() == QLatin1String("err")) { errMsg = elem.text(); int errCode = elem.attribute(QLatin1String("code") , QLatin1String("0")).toInt(); switch (errCode) { case 96: case 97: errMsg = i18n("Signature problem. Please try again later"); break; case 105: errMsg = i18n("The requested service is temporarily unavailable. Try again later"); break; default: errMsg = i18n("Unknown Error:%1. Please try again later").arg(errCode); break; } } } else { errMsg = i18n("Malformed response"); } node = node.nextSibling(); } } else { errMsg = i18n("Malformed response"); } } else { errMsg = job->errorString(); } if (!errMsg.isEmpty()) { KMessageBox::error(ui.gridLayout->widget(), errMsg, i18n("Flickr authorization")); } } void FlickrConfig::getToken() { m_token.clear(); QUrl url(QLatin1String("https://flickr.com/services/rest/")); QUrlQuery urlQuery; urlQuery.addQueryItem(QLatin1String("method"), QLatin1String("flickr.auth.getToken")); urlQuery.addQueryItem(QLatin1String("api_key"), QLatin1String(apiKey.toUtf8())); urlQuery.addQueryItem(QLatin1String("frob"), QLatin1String(m_frob.toUtf8())); urlQuery.addQueryItem(QLatin1String("api_sig"), QLatin1String(createSign("frob" + m_frob.toUtf8() + "methodflickr.auth.getToken"))); url.setQuery(urlQuery); QString errMsg; KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); job->exec(); if (!job->error()) { QDomDocument rep; rep.setContent(job->data()); QDomElement element = rep.documentElement(); if (element.tagName() == QLatin1String("rsp")) { QString res; res = element.attribute(QLatin1String("stat") , QLatin1String("fail")); QDomNode node = element.firstChild(); while (!node.isNull()) { QDomElement elem = node.toElement(); if (res == QLatin1String("ok")) { QDomNode authNode = node.firstChild(); while (!authNode.isNull()) { QDomElement elem = authNode.toElement(); if (elem.tagName() == QLatin1String("token")) { m_token = elem.text(); } if (elem.tagName() == QLatin1String("user")) { m_nsid = elem.attribute(QLatin1String("nsid")); m_username = elem.attribute(QLatin1String("username")); m_fullname = elem.attribute(QLatin1String("fullname")); } authNode = authNode.nextSibling(); } } else if (res == QLatin1String("fail")) { if (elem.tagName() == QLatin1String("err")) { errMsg = elem.text(); int errCode = elem.attribute(QLatin1String("code") , QLatin1String("0")).toInt(); switch (errCode) { case 96: case 97: case 108: errMsg = i18n("Something happens with signature. Please retry"); break; case 105: errMsg = i18n("The requested service is temporarily unavailable. Try again later"); break; default: errMsg = i18n("Something happens wrong. Error %1. Try again later").arg(errCode); break; } } } else { errMsg = i18n("Malformed response"); } node = node.nextSibling(); } } else { errMsg = i18n("Malformed response"); } } else { errMsg = job->errorString(); } if (!errMsg.isEmpty()) { KMessageBox::error(ui.gridLayout->widget(), errMsg, i18n("Flickr authorization")); return; } if (!m_token.isEmpty()) { setAuthenticated(true); FlickrConfig::save(); ui.tabWidget->setCurrentIndex(1); } else { setAuthenticated(false); } ui.authButton->setEnabled(true); } void FlickrConfig::setAuthenticated(bool authenticated) { isAuthenticated = authenticated; if (authenticated) { ui.authButton->setIcon(QIcon::fromTheme(QLatin1String("object-unlocked"))); ui.authLed->on(); ui.authLabel->setText(i18n("Authorized as %1").arg(m_username)); if (!m_fullname.isEmpty()) { ui.authLabel->setText(ui.authLabel->text() + QStringLiteral(" (%1)").arg(m_fullname.toHtmlEscaped())); } } else { ui.authButton->setIcon(QIcon::fromTheme(QLatin1String("object-locked"))); ui.authLed->off(); ui.authLabel->setText(i18n("Not authorized")); } } void FlickrConfig::slotAuthButton_clicked() { getFrob(); if (!m_frob.isEmpty()) { QUrl oUrl(QLatin1String("https://flickr.com/services/auth/?")); oUrl.setPath(oUrl.path() + QLatin1String("api_key=") + apiKey + QLatin1String("&perms=write&frob=") + m_frob + QLatin1String("&api_sig=") + QLatin1String(createSign("frob" + m_frob.toUtf8() + "permswrite"))); Choqok::openUrl(oUrl); QPushButton *btn = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-ok")), i18n("Click here when you authorized Choqok"), this); - connect(btn, SIGNAL(clicked(bool)), SLOT(getToken())); + connect(btn, &QPushButton::clicked, this, &FlickrConfig::getToken); btn->setWindowFlags(Qt::Dialog); ui.authTab->layout()->addWidget(btn); ui.authButton->setEnabled(false); } else { return; } } QByteArray FlickrConfig::createSign(QByteArray req) { return QCryptographicHash::hash(apiKeSec.toUtf8().append(req), QCryptographicHash::Md5).toHex(); } #include "flickrconfig.moc" diff --git a/plugins/uploaders/imageshack/imageshack.cpp b/plugins/uploaders/imageshack/imageshack.cpp index f9680fe8..8b50dd0f 100644 --- a/plugins/uploaders/imageshack/imageshack.cpp +++ b/plugins/uploaders/imageshack/imageshack.cpp @@ -1,132 +1,131 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "imageshack.h" #include #include #include #include #include #include #include "mediamanager.h" const static QString apiKey = QLatin1String("ZMWLXQBOfb570310607355f90c601148a3203f0f"); K_PLUGIN_FACTORY_WITH_JSON(ImageShackFactory, "choqok_imageshack.json", registerPlugin < ImageShack > ();) ImageShack::ImageShack(QObject *parent, const QList &) : Choqok::Uploader(QLatin1String("choqok_imageshack"), parent) { } ImageShack::~ImageShack() { } void ImageShack::upload(const QUrl &localUrl, const QByteArray &medium, const QByteArray &mediumType) { if (!mediumType.startsWith(QByteArray("image/"))) { Q_EMIT uploadingFailed(localUrl, i18n("Just supporting image uploading")); return; } QUrl url(QLatin1String("https://www.imageshack.us/upload_api.php")); QMap formdata; formdata[QLatin1String("key")] = apiKey.toLatin1(); formdata[QLatin1String("rembar")] = "1"; QMap mediafile; mediafile[QLatin1String("name")] = "fileupload"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; if (!job) { qCritical() << "Cannot create a http POST request!"; return; } job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: multipart/form-data; boundary=AaB03x")); mUrlMap[job] = localUrl; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotUpload(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &ImageShack::slotUpload); job->start(); } void ImageShack::slotUpload(KJob *job) { QUrl localUrl = mUrlMap.take(job); if (job->error()) { qCritical() << "Job Error:" << job->errorString(); Q_EMIT uploadingFailed(localUrl, job->errorString()); return; } else { KIO::StoredTransferJob *stj = qobject_cast(job); QDomDocument doc; doc.setContent(stj->data()); if (doc.firstChild().isNull()) { qWarning() << "Malformed response:" << stj->data(); return; } QDomElement root = doc.documentElement(); if (root.tagName() == QLatin1String("imginfo")) { QDomNode node = root.firstChild(); while (!node.isNull()) { QDomElement elm = node.toElement(); if (elm.tagName() == QLatin1String("links")) { QDomNode node2 = node.firstChild(); while (!node2.isNull()) { QDomElement elm2 = node2.toElement(); if (elm2.tagName() == QLatin1String("yfrog_link")) { Q_EMIT mediumUploaded(localUrl, elm2.text()); return; } node2 = node2.nextSibling(); } } node = node.nextSibling(); } } else { if (root.tagName() == QLatin1String("links")) { QDomNode node = root.firstChild(); if (!node.isNull()) { if (node.toElement().tagName() == QLatin1String("error")) { Q_EMIT uploadingFailed(localUrl, node.toElement().text()); return; } } } } Q_EMIT uploadingFailed(localUrl, i18n("Malformed response")); qWarning() << "Response not detected:" << stj->data(); } } -#include "imageshack.moc" \ No newline at end of file +#include "imageshack.moc" diff --git a/plugins/uploaders/mobypicture/mobypicture.cpp b/plugins/uploaders/mobypicture/mobypicture.cpp index 934e9a1c..49182388 100644 --- a/plugins/uploaders/mobypicture/mobypicture.cpp +++ b/plugins/uploaders/mobypicture/mobypicture.cpp @@ -1,167 +1,166 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "mobypicture.h" #include #include #include #include #include "accountmanager.h" #include "mediamanager.h" #include "passwordmanager.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" #include "mobypicturesettings.h" K_PLUGIN_FACTORY_WITH_JSON(MobypictureFactory, "choqok_mobypicture.json", registerPlugin < Mobypicture > ();) Mobypicture::Mobypicture(QObject *parent, const QList &) : Choqok::Uploader(QLatin1String("choqok_mobypicture"), parent) { } Mobypicture::~Mobypicture() { } void Mobypicture::upload(const QUrl &localUrl, const QByteArray &medium, const QByteArray &mediumType) { MobypictureSettings::self()->load(); KIO::StoredTransferJob *job = 0; QByteArray apiKey = "85LUKv3w6luUF6Pa"; if (MobypictureSettings::oauth()) { QString alias = MobypictureSettings::alias(); if (alias.isEmpty()) { qCritical() << "No account to use"; Q_EMIT uploadingFailed(localUrl, i18n("There is no Twitter account configured to use.")); return; } TwitterApiAccount *acc = qobject_cast (Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return; } QUrl url(QLatin1String("https://api.mobypicture.com/2.0/upload")); QMap formdata; formdata[QLatin1String("key")] = apiKey; formdata[QLatin1String("message")] = QString().toUtf8(); QMap mediafile; mediafile[QLatin1String("name")] = "media"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); QUrl requrl(QLatin1String("https://api.twitter.com/1/account/verify_credentials.json")); QByteArray credentials = acc->oauthInterface()->authorizationHeader(requrl, QNetworkAccessManager::GetOperation); QString cHeader = QLatin1String("X-Verify-Credentials-Authorization: ") + QLatin1String(credentials) + QLatin1String("\r\n"); cHeader.append(QLatin1String("X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json")); job->addMetaData(QLatin1String("customHTTPHeader"), cHeader); } else if (MobypictureSettings::basic()) { QUrl url(QLatin1String("https://api.mobypicture.com")); QString login = MobypictureSettings::login(); QString pass = Choqok::PasswordManager::self()->readPassword(QStringLiteral("mobypicture_%1") .arg(MobypictureSettings::login())); QMap formdata; formdata[QLatin1String("k")] = apiKey; formdata[QLatin1String("u")] = login.toUtf8(); formdata[QLatin1String("p")] = pass.toUtf8(); formdata[QLatin1String("s")] = "none"; formdata[QLatin1String("format")] = "json"; QMap mediafile; mediafile[QLatin1String("name")] = "i"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; job->addMetaData(QLatin1String("Authorization"), QLatin1String("Basic ") + QLatin1String(QStringLiteral("%1:%2").arg(login).arg(pass).toUtf8().toBase64())); } if (!job) { qCritical() << "Cannot create a http POST request!"; return; } job->addMetaData(QLatin1String("content-type"), QLatin1String("Content-Type: multipart/form-data; boundary=AaB03x")); mUrlMap[job] = localUrl; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotUpload(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &Mobypicture::slotUpload); job->start(); } void Mobypicture::slotUpload(KJob *job) { QUrl localUrl = mUrlMap.take(job); if (job->error()) { qCritical() << "Job Error:" << job->errorString(); Q_EMIT uploadingFailed(localUrl, job->errorString()); return; } else { KIO::StoredTransferJob *stj = qobject_cast(job); //qDebug() << stj->data(); const QJsonDocument json = QJsonDocument::fromJson(stj->data()); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); if (MobypictureSettings::oauth()) { if (map.contains(QLatin1String("errors"))) { QVariantMap err = map.value(QLatin1String("errors")).toMap(); Q_EMIT uploadingFailed(localUrl, err.value(QLatin1String("message")).toString()); } else if (map.contains(QLatin1String("media"))) { QVariantMap media = map.value(QLatin1String("media")).toMap(); Q_EMIT mediumUploaded(localUrl, media.value(QLatin1String("mediaurl")).toString()); } } if (MobypictureSettings::basic()) { if (map.value(QLatin1String("result")) == QLatin1String("0") && map.contains(QLatin1String("url"))) { Q_EMIT mediumUploaded(localUrl, map.value(QLatin1String("url")).toString()); } else { Q_EMIT uploadingFailed(localUrl, map.value(QLatin1String("message")).toString()); } } } else { Q_EMIT uploadingFailed(localUrl, i18n("Malformed response")); qWarning() << "Parse error:" << stj->data(); } } } #include "mobypicture.moc" diff --git a/plugins/uploaders/mobypicture/mobypictureconfig.cpp b/plugins/uploaders/mobypicture/mobypictureconfig.cpp index 5cca6120..9b66bb5c 100644 --- a/plugins/uploaders/mobypicture/mobypictureconfig.cpp +++ b/plugins/uploaders/mobypicture/mobypictureconfig.cpp @@ -1,108 +1,112 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "mobypictureconfig.h" +#include +#include +#include #include #include #include #include #include #include "mobypicturesettings.h" #include "accountmanager.h" #include "passwordmanager.h" K_PLUGIN_FACTORY_WITH_JSON(MobypictureConfigFactory, "choqok_mobypicture_config.json", registerPlugin < MobypictureConfig > ();) MobypictureConfig::MobypictureConfig(QWidget *parent, const QVariantList &) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_mobypicture")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mMobypictureCtl")); ui.setupUi(wd); addConfig(MobypictureSettings::self(), wd); layout->addWidget(wd); ui.cfg_pin->setEchoMode(QLineEdit::Password); - connect(ui.cfg_basic, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_login, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.cfg_pin, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.cfg_oauth, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_accountsList, SIGNAL(currentIndexChanged(int)), SLOT(emitChanged())); + connect(ui.cfg_basic, &QRadioButton::clicked, this, &MobypictureConfig::emitChanged); + connect(ui.cfg_login, &QLineEdit::textChanged, this, &MobypictureConfig::emitChanged); + connect(ui.cfg_pin, &QLineEdit::textChanged, this, &MobypictureConfig::emitChanged); + connect(ui.cfg_oauth, &QRadioButton::clicked, this, &MobypictureConfig::emitChanged); + connect(ui.cfg_accountsList, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &MobypictureConfig::emitChanged); } MobypictureConfig::~MobypictureConfig() { } void MobypictureConfig::load() { KCModule::load(); QList list = Choqok::AccountManager::self()->accounts(); for (Choqok::Account *acc: list) { if (acc->inherits("TwitterAccount")) { ui.cfg_accountsList->addItem(acc->alias()); } } MobypictureSettings::self()->load(); ui.cfg_basic->setChecked(MobypictureSettings::basic()); ui.cfg_login->setText(MobypictureSettings::login()); ui.cfg_pin->setText(Choqok::PasswordManager::self()->readPassword(QStringLiteral("mobypicture_%1") .arg(ui.cfg_login->text()))); ui.cfg_oauth->setChecked(MobypictureSettings::oauth()); ui.cfg_accountsList->setCurrentText(MobypictureSettings::alias()); emitChanged(); } void MobypictureConfig::save() { if (ui.cfg_accountsList->currentIndex() > -1) { //qDebug() << MobypictureSettings::alias(); MobypictureSettings::setAlias(ui.cfg_accountsList->currentText()); } else { MobypictureSettings::setAlias(QString()); KMessageBox::error(this, i18n("You have to configure at least one Twitter account to use this plugin.")); } MobypictureSettings::setBasic(ui.cfg_basic->isChecked()); MobypictureSettings::setLogin(ui.cfg_login->text()); Choqok::PasswordManager::self()->writePassword(QStringLiteral("mobypicture_%1").arg(ui.cfg_login->text()), ui.cfg_pin->text()); MobypictureSettings::setOauth(ui.cfg_oauth->isChecked()); MobypictureSettings::self()->save(); KCModule::save(); } void MobypictureConfig::emitChanged() { ui.cfg_login->setEnabled(ui.cfg_basic->isChecked()); ui.cfg_pin->setEnabled(ui.cfg_basic->isChecked()); ui.cfg_accountsList->setEnabled(ui.cfg_oauth->isChecked()); Q_EMIT changed(true); } #include "mobypictureconfig.moc" diff --git a/plugins/uploaders/posterous/posterous.cpp b/plugins/uploaders/posterous/posterous.cpp index aacb5b10..a118b446 100644 --- a/plugins/uploaders/posterous/posterous.cpp +++ b/plugins/uploaders/posterous/posterous.cpp @@ -1,191 +1,190 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "posterous.h" #include #include #include #include #include "accountmanager.h" #include "mediamanager.h" #include "passwordmanager.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" #include "posteroussettings.h" K_PLUGIN_FACTORY_WITH_JSON(PosterousFactory, "choqok_posterous.json", registerPlugin < Posterous > ();) Posterous::Posterous(QObject *parent, const QList &) : Choqok::Uploader(QLatin1String("choqok_posterous"), parent) { } Posterous::~Posterous() { } QString Posterous::getAuthToken(const QUrl &localUrl) { QUrl url(QLatin1String("http://posterous.com/api/2/auth/token")); QString login = PosterousSettings::login(); QString pass = Choqok::PasswordManager::self()->readPassword(QStringLiteral("posterous_%1").arg(PosterousSettings::login())); KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo); job->addMetaData(QLatin1String("customHTTPHeader"), QLatin1String("Authorization: Basic ") + QLatin1String(QStringLiteral("%1:%2").arg(login).arg(pass).toUtf8().toBase64())); job->exec(); if (!job->error()) { const QByteArray data = job->data(); const QJsonDocument json = QJsonDocument::fromJson(data); if (!json.isNull()) { QVariantMap map = json.toVariant().toMap(); if (map.contains(QLatin1String("api_token"))) { QString tkn = map.value(QLatin1String("api_token")).toString(); return tkn; } else { Q_EMIT uploadingFailed(localUrl, map.value(QLatin1String("error")).toString()); qWarning() << "Parse error:" << data; } } } else { qCritical() << "Job error:" << job->errorString(); } return QString(); } void Posterous::upload(const QUrl &localUrl, const QByteArray &medium, const QByteArray &mediumType) { PosterousSettings::self()->load(); KIO::StoredTransferJob *job = 0; if (PosterousSettings::basic()) { QString login = PosterousSettings::login(); QString pass = Choqok::PasswordManager::self()->readPassword(QStringLiteral("posterous_%1").arg(PosterousSettings::login())); QString token = getAuthToken(localUrl); if (!token.isEmpty()) { QUrl url(QLatin1String("http://posterous.com/api/2/users/me/sites/primary/posts")); QMap formdata; formdata[QLatin1String("post[title]")] = QByteArray(); formdata[QLatin1String("post[body]")] = QByteArray(); formdata[QLatin1String("autopost")] = "0"; formdata[QLatin1String("source")] = QCoreApplication::applicationName().toLatin1(); formdata[QLatin1String("api_token")] = token.toUtf8(); QMap mediafile; mediafile[QLatin1String("name")] = "media"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); job->addMetaData(QLatin1String("customHTTPHeader"), QLatin1String("Authorization: Basic ") + QLatin1String(QStringLiteral("%1:%2").arg(login).arg(pass).toUtf8().toBase64())); } } else if (PosterousSettings::oauth()) { QString alias = PosterousSettings::alias(); if (alias.isEmpty()) { qCritical() << "No account to use"; Q_EMIT uploadingFailed(localUrl, i18n("There is no Twitter account configured to use.")); return; } TwitterApiAccount *acc = qobject_cast (Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return; } QUrl url(QLatin1String("http://posterous.com/api2/upload.json")); QMap formdata; formdata[QLatin1String("source")] = QCoreApplication::applicationName().toLatin1(); formdata[QLatin1String("sourceLink")] = "http://choqok.gnufolks.org/"; QMap mediafile; mediafile[QLatin1String("name")] = "media"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo); QUrl requrl(QLatin1String("https://api.twitter.com/1/account/verify_credentials.json")); QByteArray credentials = acc->oauthInterface()->authorizationHeader(requrl, QNetworkAccessManager::GetOperation); QString cHeader = QLatin1String("X-Verify-Credentials-Authorization: ") + QLatin1String(credentials) + QLatin1String("\r\n"); cHeader.append(QLatin1String("X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json")); job->addMetaData(QLatin1String("customHTTPHeader"), cHeader); } if (!job) { qCritical() << "Cannot create a http POST request!"; return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: multipart/form-data; boundary=AaB03x")); mUrlMap[job] = localUrl; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotUpload(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &Posterous::slotUpload); job->start(); } void Posterous::slotUpload(KJob *job) { QUrl localUrl = mUrlMap.take(job); if (job->error()) { qCritical() << "Job Error:" << job->errorString(); Q_EMIT uploadingFailed(localUrl, job->errorString()); return; } else { KIO::StoredTransferJob *stj = qobject_cast(job); //qDebug() << stj->data(); const QJsonDocument json = QJsonDocument::fromJson(stj->data()); if (!json.isNull()) { const QVariantMap map = json.toVariant().toMap(); if (map.contains(QLatin1String("error"))) { Q_EMIT uploadingFailed(localUrl, map.value(QLatin1String("error")).toString()); } else { if (PosterousSettings::oauth()) { Q_EMIT mediumUploaded(localUrl, map.value(QLatin1String("url")).toString()); } if (PosterousSettings::basic()) { Q_EMIT mediumUploaded(localUrl, map.value(QLatin1String("full_url")).toString()); } } } else { Q_EMIT uploadingFailed(localUrl, i18n("Malformed response")); qWarning() << "Parse error:" << stj->data(); } } } #include "posterous.moc" diff --git a/plugins/uploaders/posterous/posterousconfig.cpp b/plugins/uploaders/posterous/posterousconfig.cpp index 29274361..32729c8b 100644 --- a/plugins/uploaders/posterous/posterousconfig.cpp +++ b/plugins/uploaders/posterous/posterousconfig.cpp @@ -1,109 +1,113 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "posterousconfig.h" +#include +#include +#include #include #include #include #include #include #include "accountmanager.h" #include "passwordmanager.h" #include "posteroussettings.h" K_PLUGIN_FACTORY_WITH_JSON(PosterousConfigFactory, "choqok_posterous_config.json", registerPlugin < PosterousConfig > ();) PosterousConfig::PosterousConfig(QWidget *parent, const QVariantList &) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_posterous")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mPosterousCtl")); ui.setupUi(wd); addConfig(PosterousSettings::self(), wd); layout->addWidget(wd); ui.cfg_password->setEchoMode(QLineEdit::Password); - connect(ui.cfg_basic, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_login, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.cfg_password, SIGNAL(textChanged(QString)), SLOT(emitChanged())); - connect(ui.cfg_oauth, SIGNAL(clicked(bool)), SLOT(emitChanged())); - connect(ui.cfg_accountsList, SIGNAL(currentIndexChanged(int)), SLOT(emitChanged())); + connect(ui.cfg_basic, &QRadioButton::clicked, this, &PosterousConfig::emitChanged); + connect(ui.cfg_login, &QLineEdit::textChanged, this, &PosterousConfig::emitChanged); + connect(ui.cfg_password, &QLineEdit::textChanged, this, &PosterousConfig::emitChanged); + connect(ui.cfg_oauth, &QRadioButton::clicked, this, &PosterousConfig::emitChanged); + connect(ui.cfg_accountsList, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &PosterousConfig::emitChanged); } PosterousConfig::~PosterousConfig() { } void PosterousConfig::load() { KCModule::load(); QList list = Choqok::AccountManager::self()->accounts(); for (Choqok::Account *acc: list) { if (acc->inherits("TwitterAccount")) { ui.cfg_accountsList->addItem(acc->alias()); } } PosterousSettings::self()->load(); ui.cfg_basic->setChecked(PosterousSettings::basic()); ui.cfg_login->setText(PosterousSettings::login()); ui.cfg_password->setText(Choqok::PasswordManager::self()->readPassword(QStringLiteral("posterous_%1") .arg(ui.cfg_login->text()))); ui.cfg_oauth->setChecked(PosterousSettings::oauth()); ui.cfg_accountsList->setCurrentText(PosterousSettings::alias()); emitChanged(); } void PosterousConfig::save() { if (ui.cfg_accountsList->currentIndex() > -1) { PosterousSettings::setAlias(ui.cfg_accountsList->currentText()); //qDebug() << PosterousSettings::alias(); } else { PosterousSettings::setAlias(QString()); KMessageBox::error(this, i18n("You have to configure at least one Twitter account to use this plugin.")); } PosterousSettings::setBasic(ui.cfg_basic->isChecked()); PosterousSettings::setLogin(ui.cfg_login->text()); Choqok::PasswordManager::self()->writePassword(QStringLiteral("posterous_%1").arg(ui.cfg_login->text()), ui.cfg_password->text()); PosterousSettings::setOauth(ui.cfg_oauth->isChecked()); PosterousSettings::self()->save(); KCModule::save(); } void PosterousConfig::emitChanged() { ui.cfg_login->setEnabled(ui.cfg_basic->isChecked()); ui.cfg_password->setEnabled(ui.cfg_basic->isChecked()); ui.cfg_accountsList->setEnabled(ui.cfg_oauth->isChecked()); Q_EMIT changed(true); } #include "posterousconfig.moc" diff --git a/plugins/uploaders/twitgoo/twitgoo.cpp b/plugins/uploaders/twitgoo/twitgoo.cpp index 66ded175..3b16ce3a 100644 --- a/plugins/uploaders/twitgoo/twitgoo.cpp +++ b/plugins/uploaders/twitgoo/twitgoo.cpp @@ -1,130 +1,129 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitgoo.h" #include #include #include #include #include "accountmanager.h" #include "mediamanager.h" #include "passwordmanager.h" #include "twitterapiaccount.h" #include "twitterapimicroblog.h" #include "twitgoosettings.h" K_PLUGIN_FACTORY_WITH_JSON(TwitgooFactory, "choqok_twitgoo.json", registerPlugin < Twitgoo > ();) Twitgoo::Twitgoo(QObject *parent, const QList &) : Choqok::Uploader(QLatin1String("choqok_twitgoo"), parent) { } Twitgoo::~Twitgoo() { } void Twitgoo::upload(const QUrl &localUrl, const QByteArray &medium, const QByteArray &mediumType) { TwitgooSettings::self()->load(); QString alias = TwitgooSettings::alias(); if (alias.isEmpty()) { qCritical() << "No account to use"; Q_EMIT uploadingFailed(localUrl, i18n("There is no Twitter account configured to use.")); return; } TwitterApiAccount *acc = qobject_cast (Choqok::AccountManager::self()->findAccount(alias)); if (!acc) { return; } QUrl url(QLatin1String("http://twitgoo.com/api/upload")); QMap formdata; formdata[QLatin1String("source")] = QCoreApplication::applicationName().toLatin1(); formdata[QLatin1String("format")] = "json"; QMap mediafile; mediafile[QLatin1String("name")] = "media"; mediafile[QLatin1String("filename")] = localUrl.fileName().toUtf8(); mediafile[QLatin1String("mediumType")] = mediumType; mediafile[QLatin1String("medium")] = medium; QList< QMap > listMediafiles; listMediafiles.append(mediafile); QByteArray data = Choqok::MediaManager::createMultipartFormData(formdata, listMediafiles); KIO::StoredTransferJob *job = KIO::storedHttpPost(data, url, KIO::HideProgressInfo) ; job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json")); QUrl requrl(QLatin1String("https://api.twitter.com/1/account/verify_credentials.json")); QByteArray credentials = acc->oauthInterface()->authorizationHeader(requrl, QNetworkAccessManager::GetOperation); job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("X-Verify-Credentials-Authorization: ") + QLatin1String(credentials)); if (!job) { qCritical() << "Cannot create a http POST request!"; return; } job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: multipart/form-data; boundary=AaB03x")); mUrlMap[job] = localUrl; - connect(job, SIGNAL(result(KJob*)), - SLOT(slotUpload(KJob*))); + connect(job, &KIO::StoredTransferJob::result, this, &Twitgoo::slotUpload); job->start(); } void Twitgoo::slotUpload(KJob *job) { QUrl localUrl = mUrlMap.take(job); if (job->error()) { qCritical() << "Job Error:" << job->errorString(); Q_EMIT uploadingFailed(localUrl, job->errorString()); return; } else { KIO::StoredTransferJob *stj = qobject_cast(job); //qDebug() << stj->data(); const QJsonDocument json = QJsonDocument::fromJson(stj->data()); if (!json.isNull()) { QVariantMap map = json.toVariant().toMap(); if (map.value(QLatin1String("status")) == QLatin1String("fail")) { QVariantMap err = map.value(QLatin1String("err")).toMap(); Q_EMIT uploadingFailed(localUrl, err.value(QLatin1String("err_msg")).toString()); } else if (map.value(QLatin1String("status")) == QLatin1String("ok")) { TwitgooSettings::self()->load(); QString val = TwitgooSettings::directLink() ? QLatin1String("imageurl") : QLatin1String("mediaurl"); Q_EMIT mediumUploaded(localUrl, map.value(val).toString()); } } else { Q_EMIT uploadingFailed(localUrl, i18n("Malformed response")); qWarning() << "Parse error:" << stj->data(); } } } #include "twitgoo.moc" diff --git a/plugins/uploaders/twitgoo/twitgooconfig.cpp b/plugins/uploaders/twitgoo/twitgooconfig.cpp index 287fd9af..f2110e83 100644 --- a/plugins/uploaders/twitgoo/twitgooconfig.cpp +++ b/plugins/uploaders/twitgoo/twitgooconfig.cpp @@ -1,90 +1,93 @@ /* This file is part of Choqok, the KDE micro-blogging client Copyright (C) 2010-2012 Andrey Esin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "twitgooconfig.h" +#include +#include #include #include #include #include #include #include "accountmanager.h" #include "twitgoosettings.h" K_PLUGIN_FACTORY_WITH_JSON(TwitgooConfigFactory, "choqok_twitgoo_config.json", registerPlugin < TwitgooConfig > ();) TwitgooConfig::TwitgooConfig(QWidget *parent, const QVariantList &) : KCModule(KAboutData::pluginData(QLatin1String("kcm_choqok_twitgoo")), parent) { QVBoxLayout *layout = new QVBoxLayout(this); QWidget *wd = new QWidget(this); wd->setObjectName(QLatin1String("mTwitgooCtl")); ui.setupUi(wd); addConfig(TwitgooSettings::self(), wd); layout->addWidget(wd); - connect(ui.cfg_accountsList, SIGNAL(currentIndexChanged(int)), SLOT(emitChanged())); - connect(ui.cfg_directLink, SIGNAL(stateChanged(int)), SLOT(emitChanged())); + connect(ui.cfg_accountsList, (void (QComboBox::*)(int))&QComboBox::currentIndexChanged, + this, &TwitgooConfig::emitChanged); + connect(ui.cfg_directLink, &QCheckBox::stateChanged, this, &TwitgooConfig::emitChanged); } TwitgooConfig::~TwitgooConfig() { } void TwitgooConfig::load() { KCModule::load(); QList list = Choqok::AccountManager::self()->accounts(); for (Choqok::Account *acc: list) { if (acc->inherits("TwitterAccount")) { ui.cfg_accountsList->addItem(acc->alias()); } } TwitgooSettings::self()->load(); ui.cfg_accountsList->setCurrentText(TwitgooSettings::alias()); ui.cfg_directLink->setChecked(TwitgooSettings::directLink()); } void TwitgooConfig::save() { if (ui.cfg_accountsList->currentIndex() > -1) { TwitgooSettings::setAlias(ui.cfg_accountsList->currentText()); //qDebug() << TwitgooSettings::alias(); } else { TwitgooSettings::setAlias(QString()); KMessageBox::error(this, i18n("You have to configure at least one Twitter account to use this plugin.")); } TwitgooSettings::setDirectLink(ui.cfg_directLink->isChecked()); TwitgooSettings::self()->save(); KCModule::save(); } void TwitgooConfig::emitChanged() { Q_EMIT changed(true); } #include "twitgooconfig.moc" diff --git a/plugins/videopreview/videopreview.cpp b/plugins/videopreview/videopreview.cpp index 3a37ddfe..e99f4191 100644 --- a/plugins/videopreview/videopreview.cpp +++ b/plugins/videopreview/videopreview.cpp @@ -1,274 +1,269 @@ /* This file is part of Choqok, the KDE micro-blogging client Based on the imagepreview extension Copyright (C) 2010-2012 Emanuele Bigiarini Copyright (C) 2008-2012 Mehrdad Momeny This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses/ */ #include "videopreview.h" #include #include #include #include #include #include #include #include #include "choqokuiglobal.h" #include "postwidget.h" #include "notifymanager.h" #include "mediamanager.h" #include "textbrowser.h" #include "shortenmanager.h" K_PLUGIN_FACTORY_WITH_JSON(VideoPreviewFactory, "choqok_videopreview.json", registerPlugin < VideoPreview > ();) const QRegExp VideoPreview::mYouTuRegExp(QLatin1String("(https?://youtu.[^\\s<>\"]+[^!,\\.\\s<>'\\\"\\]])")); const QRegExp VideoPreview::mYouTubeRegExp(QLatin1String("(https?://www.youtube.[^\\s<>\"]+[^!,\\.\\s<>'\\\"\\]])")); const QRegExp VideoPreview::mVimeoRegExp(QLatin1String("(https?://(.+)?vimeo.com/(.+)[&]?)")); const QRegExp VideoPreview::mYouTuCode(QLatin1String("youtu.(.+)/(.+)[?&]?")); VideoPreview::VideoPreview(QObject *parent, const QList< QVariant > &) : Choqok::Plugin(QLatin1String("choqok_videopreview"), parent) , state(Stopped) { - connect(Choqok::UI::Global::SessionManager::self(), - SIGNAL(newPostWidgetAdded(Choqok::UI::PostWidget*,Choqok::Account*,QString)), - this, - SLOT(slotAddNewPostWidget(Choqok::UI::PostWidget*))); - connect(Choqok::ShortenManager::self(), - SIGNAL(newUnshortenedUrl(Choqok::UI::PostWidget*,QUrl,QUrl)), - this, - SLOT(slotNewUnshortenedUrl(Choqok::UI::PostWidget*,QUrl,QUrl))); + connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded, + this, &VideoPreview::slotAddNewPostWidget); + connect(Choqok::ShortenManager::self(), &Choqok::ShortenManager::newUnshortenedUrl, + this, &VideoPreview::slotNewUnshortenedUrl); } VideoPreview::~VideoPreview() { } void VideoPreview::slotAddNewPostWidget(Choqok::UI::PostWidget *newWidget) { postsQueue.enqueue(newWidget); if (state == Stopped) { state = Running; QTimer::singleShot(1000, this, SLOT(startParsing())); } } void VideoPreview::slotNewUnshortenedUrl(Choqok::UI::PostWidget *widget, const QUrl &fromUrl, const QUrl &toUrl) { Q_UNUSED(fromUrl) if (mYouTubeRegExp.indexIn(toUrl.toDisplayString()) != -1) { QUrl thisurl(mYouTubeRegExp.cap(0)); QUrlQuery thisurlQuery(thisurl); QUrl thumbUrl = parseYoutube(thisurlQuery.queryItemValue(QLatin1String("v")), widget); - connect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - SLOT(slotImageFetched(QUrl,QPixmap))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &VideoPreview::slotImageFetched); Choqok::MediaManager::self()->fetchImage(thumbUrl, Choqok::MediaManager::Async); } else if (mVimeoRegExp.indexIn(toUrl.toDisplayString()) != -1) { QUrl thumbUrl = parseVimeo(mVimeoRegExp.cap(3), widget); - connect(Choqok::MediaManager::self(), SIGNAL(imageFetched(QUrl,QPixmap)), - SLOT(slotImageFetched(QUrl,QPixmap))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &VideoPreview::slotImageFetched); Choqok::MediaManager::self()->fetchImage(thumbUrl, Choqok::MediaManager::Async); } } void VideoPreview::startParsing() { int i = 8; while (!postsQueue.isEmpty() && i > 0) { parse(postsQueue.dequeue()); --i; } if (postsQueue.isEmpty()) { state = Stopped; } else { QTimer::singleShot(500, this, SLOT(startParsing())); } } void VideoPreview::parse(QPointer postToParse) { if (!postToParse) { return; } int pos = 0; int pos1 = 0; int pos2 = 0; int pos3 = 0; QList thumbList; QString content = postToParse->currentPost()->content; while (((pos1 = mYouTuRegExp.indexIn(content, pos)) != -1) | ((pos2 = mYouTubeRegExp.indexIn(content, pos)) != -1) | ((pos3 = mVimeoRegExp.indexIn(content, pos)) != -1)) { if (pos1 >= 0) { pos = pos1 + mYouTuRegExp.matchedLength(); if (mYouTuCode.indexIn(mYouTuRegExp.cap(0)) != -1) { thumbList << parseYoutube(mYouTuCode.cap(2), postToParse); } } else if (pos2 >= 0) { pos = pos2 + mYouTubeRegExp.matchedLength(); QUrl thisurl(mYouTubeRegExp.cap(0)); QUrlQuery thisurlQuery(thisurl); thumbList << parseYoutube(thisurlQuery.queryItemValue(QLatin1String("v")), postToParse); } else if (pos3 >= 0) { pos = pos3 + mVimeoRegExp.matchedLength(); thumbList << parseVimeo(mVimeoRegExp.cap(3), postToParse); } } for (const QUrl &thumb_url: thumbList) { - connect(Choqok::MediaManager::self(), - SIGNAL(imageFetched(QUrl,QPixmap)), - SLOT(slotImageFetched(QUrl,QPixmap))); + connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched, + this, &VideoPreview::slotImageFetched); Choqok::MediaManager::self()->fetchImage(thumb_url, Choqok::MediaManager::Async); } } QUrl VideoPreview::parseYoutube(QString videoid, QPointer< Choqok::UI::PostWidget > postToParse) { QString youtubeUrl = QStringLiteral("https://gdata.youtube.com/feeds/api/videos/%1").arg(videoid); QUrl th_url(youtubeUrl); KIO::StoredTransferJob *job = KIO::storedGet(th_url, KIO::NoReload, KIO::HideProgressInfo); KJobWidgets::setWindow(job, Choqok::UI::Global::mainWindow()); QString title, description; QUrl thumb_url; job->exec(); if (!job->error()) { QDomDocument document; document.setContent(job->data()); QDomElement root = document.documentElement(); if (!root.isNull()) { QDomElement node; node = root.firstChildElement(QLatin1String("title")); if (!node.isNull()) { title = QString(node.text()); } node = root.firstChildElement(QLatin1String("media:group")); node = node.firstChildElement(QLatin1String("media:description")); if (!node.isNull()) { description = QString(node.text()); } node = node.nextSiblingElement(QLatin1String("media:thumbnail")); if (!node.isNull()) { thumb_url = QUrl::fromUserInput(node.attributeNode(QLatin1String("url")).value()); } } description = description.left(70); mParsingList.insert(thumb_url, postToParse); mBaseUrlMap.insert(thumb_url, QLatin1String("https://www.youtube.com/watch?v=") + videoid); mTitleVideoMap.insert(thumb_url, title); mDescriptionVideoMap.insert(thumb_url, description); } else { qCritical() << "Youtube XML response is NULL!"; } return thumb_url; } QUrl VideoPreview::parseVimeo(QString videoid, QPointer< Choqok::UI::PostWidget > postToParse) { QString vimeoUrl = QStringLiteral("https://vimeo.com/api/v2/video/%1.xml").arg(videoid); QUrl th_url(vimeoUrl); QEventLoop loop; KIO::StoredTransferJob *job = KIO::storedGet(th_url, KIO::NoReload, KIO::HideProgressInfo); KJobWidgets::setWindow(job, Choqok::UI::Global::mainWindow()); QString title, description; QUrl thumb_url; job->exec(); if (!job->error()) { QDomDocument document; document.setContent(job->data()); QDomElement root = document.documentElement(); if (!root.isNull()) { QDomElement videotag; videotag = root.firstChildElement(QLatin1String("video")); if (!videotag.isNull()) { QDomElement node; node = videotag.firstChildElement(QLatin1String("title")); if (!node.isNull()) { title = QString(node.text()); } node = videotag.firstChildElement(QLatin1String("description")); if (!node.isNull()) { description = QString(node.text()); } node = videotag.firstChildElement(QLatin1String("thumbnail_small")); if (!node.isNull()) { thumb_url = QUrl::fromUserInput(node.text()); } } } description = description.left(70); mParsingList.insert(thumb_url, postToParse); mBaseUrlMap.insert(thumb_url, QLatin1String("https://vimeo.com/") + videoid); mTitleVideoMap.insert(thumb_url, title); mDescriptionVideoMap.insert(thumb_url, description); } else { qCritical() << "Vimeo XML response is NULL!"; } return thumb_url; } void VideoPreview::slotImageFetched(const QUrl &remoteUrl, const QPixmap &pixmap) { Choqok::UI::PostWidget *postToParse = mParsingList.take(remoteUrl); QString baseUrl = mBaseUrlMap.take(remoteUrl); QString title = mTitleVideoMap.take(remoteUrl); QString description = mDescriptionVideoMap.take(remoteUrl); if (!postToParse) { return; } QString content = postToParse->content(); QUrl imgU(remoteUrl); imgU.setScheme(QLatin1String("img")); postToParse->mainWidget()->document()->addResource(QTextDocument::ImageResource, imgU, pixmap); QString temp(QLatin1String("
")); temp.append(QLatin1String("")); temp.append(QLatin1String("") + description + QLatin1String("
") + title + QLatin1String("
")); content.append(temp); postToParse->setContent(content); } #include "videopreview.moc"