diff --git a/libpublictransporthelper/serviceproviderdatadialog.cpp b/libpublictransporthelper/serviceproviderdatadialog.cpp index 83c5983..67e1240 100644 --- a/libpublictransporthelper/serviceproviderdatadialog.cpp +++ b/libpublictransporthelper/serviceproviderdatadialog.cpp @@ -1,495 +1,495 @@ /* * Copyright 2012 Friedrich Pülz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library 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. */ // Header #include "serviceproviderdatadialog.h" // Own includes #include "ui_providerData.h" // KDE includes #include #include #include #include #include #include #include #include #include /** @brief Namespace for the publictransport helper library. */ namespace PublicTransport { class ServiceProviderDataWidgetPrivate { public: ServiceProviderDataWidgetPrivate( const QString &providerId, ServiceProviderDataWidget::Options _options, ServiceProviderDataWidget *q ) : q(q), providerId(providerId), options(_options), feedSizeInBytes(0) { uiProviderData.setupUi( q ); }; void updateIcon( const QIcon &icon ) { uiProviderData.icon->setPixmap( icon.pixmap( 32 ) ); } void update( const Plasma::DataEngine::Data &data ) { providerType = data["type"].toString(); uiProviderData.type->setText( providerType ); state = data["state"].toString(); stateData = data["stateData"].toHash(); uiProviderData.state->setText( stateData["statusMessage"].toString() ); // Hide all widgets except for the status message for erroneous providers // because the other fields are empty const bool hasError = state == QLatin1String("error"); uiProviderData.icon->setVisible( !hasError ); uiProviderData.version->setVisible( !hasError ); uiProviderData.line->setVisible( !hasError ); uiProviderData.lblUrl->setVisible( !hasError ); uiProviderData.url->setVisible( !hasError ); uiProviderData.lblAuthor->setVisible( !hasError ); uiProviderData.author->setVisible( !hasError ); uiProviderData.lblType->setVisible( !hasError ); uiProviderData.type->setVisible( !hasError ); uiProviderData.lblFileName->setVisible( !hasError ); uiProviderData.fileName->setVisible( !hasError ); uiProviderData.lblFeatures->setVisible( !hasError ); uiProviderData.features->setVisible( !hasError ); uiProviderData.lblDescription->setVisible( !hasError ); uiProviderData.description->setVisible( !hasError ); const QString type = data["type"].toString(); if ( type != QLatin1String("GTFS") ) { uiProviderData.lblGtfsFeed->hide(); uiProviderData.gtfsFeed->hide(); uiProviderData.importGtfsFeedButton->hide(); uiProviderData.updateGtfsDatabaseButton->hide(); uiProviderData.deleteGtfsDatabaseButton->hide(); uiProviderData.progressBar->hide(); } else { // Is a GTFS provider const QString feedUrl = data["feedUrl"].toString(); uiProviderData.lblGtfsFeed->show(); uiProviderData.gtfsFeed->show(); if ( state == QLatin1String("ready") ) { uiProviderData.importGtfsFeedButton->setEnabled( false ); uiProviderData.deleteGtfsDatabaseButton->setEnabled( true ); feedSizeInBytes = stateData["gtfsDatabaseSize"].toInt(); uiProviderData.gtfsFeed->setText( i18nc("@info:label", "%1,%2 disk space used", feedUrl, KGlobal::locale()->formatByteSize(feedSizeInBytes)) ); } else { uiProviderData.importGtfsFeedButton->setEnabled( state == QLatin1String("gtfs_feed_import_pending") ); uiProviderData.deleteGtfsDatabaseButton->setEnabled( false ); uiProviderData.gtfsFeed->setText( i18nc("@info:label", "%1", feedUrl) ); } if ( state == QLatin1String("importing_gtfs_feed") ) { uiProviderData.progressBar->setValue( stateData["progress"].toInt() ); uiProviderData.progressBar->show(); } else { uiProviderData.progressBar->hide(); } } // Set the tooltip for the "Delete GTFS Database" button also if it gets hidden, // because ServiceProviderDataDialog may use this tooltip for it's own (dialog) button uiProviderData.deleteGtfsDatabaseButton->setToolTip( i18nc("@info:tooltip", "Delete GTFS Database" "The GTFS database contains all data imported from the GTFS " "feed. If you delete the database now the GTFS feed needs to be " "imported again to make this service provider usable again." "By deleting the database %1 disk space get freed.", KGlobal::locale()->formatByteSize(feedSizeInBytes) ) ); if ( !options.testFlag(ServiceProviderDataWidget::ShowDatabaseControlButtons) ) { uiProviderData.lblOperations->hide(); uiProviderData.importGtfsFeedButton->hide(); uiProviderData.updateGtfsDatabaseButton->hide(); uiProviderData.deleteGtfsDatabaseButton->hide(); } uiProviderData.serviceProviderName->setText(data["name"].toString() ); uiProviderData.version->setText( i18nc("@info/plain", "Version %1", data["version"].toString()) ); uiProviderData.url->setUrl( data["url"].toString() ); uiProviderData.url->setText( QString("%1").arg( data["url"].toString()) ); uiProviderData.fileName->setUrl( data["fileName"].toString() ); uiProviderData.fileName->setText( QString("%1").arg( data["fileName"].toString()) ); QString scriptFileName = data["scriptFileName"].toString(); if ( scriptFileName.isEmpty() ) { uiProviderData.lblScriptFileName->setVisible( false ); uiProviderData.scriptFileName->setVisible( false ); } else { uiProviderData.lblScriptFileName->setVisible( true ); uiProviderData.scriptFileName->setVisible( true ); uiProviderData.scriptFileName->setUrl( scriptFileName ); uiProviderData.scriptFileName->setText( QString("%1") .arg(scriptFileName) ); } if ( data["email"].toString().isEmpty() ) { uiProviderData.author->setText( data["author"].toString() ); } else { uiProviderData.author->setText( QString("%1 (%3)") .arg(data["author"].toString()) .arg(data["email"].toString()) .arg(data["shortAuthor"].toString()) ); uiProviderData.author->setToolTip( i18nc("@info", "Write an email to %1 (%3)", data["author"].toString(), data["email"].toString(), data["shortAuthor"].toString()) ); } uiProviderData.description->setText( data["description"].toString() ); uiProviderData.features->setText( data["featureNames"].toStringList().join(", ") ); QStringList changelogEntries = data["changelog"].toStringList(); if ( changelogEntries.isEmpty() ) { uiProviderData.lblChangelog->hide(); uiProviderData.changelog->hide(); } else { QString changelog("
    "); foreach ( const QString &entry, changelogEntries ) { int pos = entry.indexOf(':'); if ( pos == -1 ) { changelog.append( QString("
  • %1
  • ").arg(entry) ); } else { QString e = entry; changelog.append( QString("
  • %1
  • ") .arg(e.insert(pos + 1, QLatin1String(""))) ); } } changelog.append( QLatin1String("
") ); uiProviderData.changelog->setHtml( changelog ); } q->emit providerStateChanged( state, stateData ); }; QString providerFileName() const { return uiProviderData.fileName->url(); }; ServiceProviderDataWidget *q; Ui::providerData uiProviderData; QString providerId; ServiceProviderDataWidget::Options options; QString providerType; QString state; QVariantHash stateData; qint64 feedSizeInBytes; }; ServiceProviderDataWidget::ServiceProviderDataWidget( const QString &providerId, ServiceProviderDataWidget::Options options, QWidget *parent ) : QWidget(parent), d_ptr(new ServiceProviderDataWidgetPrivate(providerId, options, this)) { Q_D( ServiceProviderDataWidget ); Plasma::DataEngineConsumer *consumer; Plasma::PluginLoader::self()->loadDataEngine( "publictransport" ); Plasma::PluginLoader::self()->loadDataEngine( "favicons" ); Plasma::DataEngine *engine = consumer->dataEngine( "publictransport" ); engine->connectSource( "ServiceProvider " + providerId, this ); connect( d->uiProviderData.deleteGtfsDatabaseButton, SIGNAL(pressed()), this, SLOT(deleteGtfsDatabase()) ); connect( d->uiProviderData.importGtfsFeedButton, SIGNAL(pressed()), this, SLOT(importGtfsFeed()) ); connect( d->uiProviderData.updateGtfsDatabaseButton, SIGNAL(pressed()), this, SLOT(updateGtfsDatabase()) ); } ServiceProviderDataWidget::~ServiceProviderDataWidget() { Q_D( ServiceProviderDataWidget ); Plasma::DataEngineConsumer *consumer; // Disconnect sources to prevent warnings (No such slot QObject::dataUpdated...) Plasma::DataEngine *engine = consumer->dataEngine("publictransport"); engine->disconnectSource( "ServiceProvider " + d->providerId, this ); delete d_ptr; consumer->~DataEngineConsumer(); } void ServiceProviderDataWidget::dataUpdated( const QString &sourceName, const Plasma::DataEngine::Data &data ) { Q_D( ServiceProviderDataWidget ); Plasma::DataEngineConsumer *consumer; if ( sourceName == "ServiceProvider " + d->providerId ) { d->update( data ); // Request favicon Plasma::DataEngine *favIconEngine = consumer->dataEngine( "favicons" ); if ( favIconEngine ) { QString favIconSource = data["url"].toString(); favIconEngine->connectSource( favIconSource, this ); } } else { // Favicon of a service provider arrived QPixmap favicon( QPixmap::fromImage( data["Icon"].value() ) ); if ( favicon.isNull() ) { // No favicon found for sourceName; favicon = QPixmap( 16, 16 ); favicon.fill( Qt::transparent ); } d->updateIcon( QIcon(favicon) ); } } QString ServiceProviderDataWidget::providerType() const { Q_D( const ServiceProviderDataWidget ); return d->providerType; } QString ServiceProviderDataWidget::providerState() const { Q_D( const ServiceProviderDataWidget ); return d->state; } QVariantHash ServiceProviderDataWidget::providerStateData() const { Q_D( const ServiceProviderDataWidget ); return d->stateData; } class ServiceProviderDataDialogPrivate { friend class ServiceProviderDataWidget; public: ServiceProviderDataDialogPrivate( ServiceProviderDataDialog *q ) : q(q), widget(0) {}; void updateDialogButtons() { if ( widget->providerType() != QLatin1String("GTFS") ) { q->showButton( KDialog::User2, false ); q->showButton( KDialog::User3, false ); return; } if ( q->button(KDialog::User2) ) { KPushButton *button; if ( widget->providerState() == QLatin1String("gtfs_feed_import_pending") ) { button = widget->d_ptr->uiProviderData.importGtfsFeedButton; q->enableButton( KDialog::User2, true ); } else if ( widget->providerState() == QLatin1String("ready") ) { button = widget->d_ptr->uiProviderData.deleteGtfsDatabaseButton; q->enableButton( KDialog::User2, true ); } else { button = widget->d_ptr->uiProviderData.importGtfsFeedButton; q->enableButton( KDialog::User2, false ); } q->setButtonIcon( KDialog::User2, button->icon() ); q->setButtonText( KDialog::User2, button->text() ); q->setButtonToolTip( KDialog::User2, button->toolTip() ); q->showButton( KDialog::User2, true ); } if ( q->button(KDialog::User3) ) { const bool isReady = widget->providerState() == QLatin1String("ready"); const bool updateAvailable = isReady && widget->providerStateData().value("updatable").toBool(); q->showButton( KDialog::User3, isReady ); q->enableButton( KDialog::User3, updateAvailable ); } }; ServiceProviderDataDialog *q; ServiceProviderDataWidget *widget; }; ServiceProviderDataDialog::ServiceProviderDataDialog( const QString &providerId, ServiceProviderDataDialog::Options options, QWidget *parent ) : KDialog(parent), d_ptr(new ServiceProviderDataDialogPrivate(this)) { Q_D( ServiceProviderDataDialog ); d->widget = new ServiceProviderDataWidget( providerId, ServiceProviderDataWidget::NoOption, this ); connect( d->widget, SIGNAL(providerStateChanged(QString,QVariantHash)), this, SLOT(providerStateChanged(QString,QVariantHash)) ); setModal( true ); setButtons( KDialog::Ok ); setMainWidget( d->widget ); setWindowTitle( i18nc("@title:window", "Service Provider Information") ); setWindowIcon( QIcon::fromTheme("help-about") ); ButtonCodes buttonCodes = Ok; if ( options.testFlag(ShowOpenInTimetableMateButton) ) { buttonCodes |= User1; // Add "Open in TimetableMate..." button } if ( options.testFlag(ShowDatabaseControlButtons) ) { buttonCodes |= User2; // Add delete/import button buttonCodes |= User3; // Add update button } setButtons( buttonCodes ); if ( options.testFlag(ShowOpenInTimetableMateButton) ) { setButtonIcon( User1, QIcon::fromTheme("document-open") ); setButtonText( User1, i18nc("@action:button", "Open in TimetableMate...") ); } KPushButton *button = d->widget->d_ptr->uiProviderData.updateGtfsDatabaseButton; setButtonIcon( User3, button->icon() ); setButtonText( User3, button->text() ); setButtonToolTip( User3, button->toolTip() ); d->updateDialogButtons(); } ServiceProviderDataDialog::~ServiceProviderDataDialog() { delete d_ptr; } ServiceProviderDataWidget *ServiceProviderDataDialog::providerDataWidget() const { Q_D( const ServiceProviderDataDialog ); return d->widget; } void ServiceProviderDataDialog::providerStateChanged( const QString &state, const QVariantHash &stateData ) { Q_UNUSED( state ) Q_UNUSED( stateData ) Q_D( ServiceProviderDataDialog ); // TODO Enable the "Delete GTFS Database" button only when the provider is ready, // ie. the GTFS feed was imported d->updateDialogButtons(); } void ServiceProviderDataDialog::slotButtonClicked( int button ) { Q_D( ServiceProviderDataDialog ); switch ( button ) { case User1: openInTimetableMate(); break; case User2: if ( d->widget->providerState() == QLatin1String("ready") ) { d->widget->deleteGtfsDatabase(); } else { d->widget->importGtfsFeed(); } break; case User3: d->widget->updateGtfsDatabase(); break; default: KDialog::slotButtonClicked( button ); break; } } void ServiceProviderDataDialog::openInTimetableMate() { Q_D( ServiceProviderDataDialog ); QString error; int result = KToolInvocation::startServiceByDesktopName( "timetablemate", d->widget->d_ptr->providerFileName(), &error ); if ( result != 0 ) { KMessageBox::error( this, i18nc("@info", "TimetableMate couldn't be started, error message was: '%1'", error) ); } } void ServiceProviderDataWidget::deleteGtfsDatabase() { Q_D( ServiceProviderDataWidget ); Plasma::DataEngineConsumer *consumer; if ( KMessageBox::warningContinueCancel(this, i18nc("@info", "Delete GTFS database" "Do you really want to delete the GTFS database? You will need to import the " "GTFS feed again to use this service provider again." "By deleting the database %1 disk space get freed.", KGlobal::locale()->formatByteSize(d->feedSizeInBytes))) == KMessageBox::Continue ) { Plasma::DataEngine *engine = consumer->dataEngine("publictransport"); Plasma::Service *gtfsService = engine->serviceForSource("GTFS"); - KConfigGroup op = gtfsService->operationDescription("deleteGtfsDatabase"); - op.writeEntry( "serviceProviderId", d->providerId ); - Plasma::ServiceJob *deleteJob = gtfsService->startOperationCall( op ); + QVariantMap serviceMap= gtfsService->operationDescription("deleteGtfsDatabase"); + serviceMap.insert("serviceProviderId", d->providerId); + Plasma::ServiceJob *deleteJob = gtfsService->startOperationCall( serviceMap ); connect( deleteJob, SIGNAL(result(KJob*)), this, SLOT(deletionFinished(KJob*)) ); connect( deleteJob, SIGNAL(finished(KJob*)), gtfsService, SLOT(deleteLater()) ); } } void ServiceProviderDataWidget::importGtfsFeed() { Q_D( ServiceProviderDataWidget ); Plasma::DataEngineConsumer *consumer; Plasma::DataEngine *engine = consumer->dataEngine("publictransport"); Plasma::Service *gtfsService = engine->serviceForSource("GTFS"); - KConfigGroup op = gtfsService->operationDescription("importGtfsFeed"); - op.writeEntry( "serviceProviderId", d->providerId ); - Plasma::ServiceJob *importJob = gtfsService->startOperationCall( op ); + QVariantMap serviceMap = gtfsService->operationDescription("importGtfsFeed"); + serviceMap.insert( "serviceProviderId", d->providerId ); + Plasma::ServiceJob *importJob = gtfsService->startOperationCall( serviceMap ); connect( importJob, SIGNAL(finished(KJob*)), gtfsService, SLOT(deleteLater()) ); } void ServiceProviderDataWidget::updateGtfsDatabase() { Q_D( ServiceProviderDataWidget ); Plasma::DataEngineConsumer *consumer; Plasma::DataEngine *engine = consumer->dataEngine("publictransport"); Plasma::Service *gtfsService = engine->serviceForSource("GTFS"); - KConfigGroup op = gtfsService->operationDescription("updateGtfsDatabase"); - op.writeEntry( "serviceProviderId", d->providerId ); - Plasma::ServiceJob *updateJob = gtfsService->startOperationCall( op ); + QVariantMap serviceMap = gtfsService->operationDescription("updateGtfsDatabase"); + serviceMap.insert( "serviceProviderId", d->providerId ); + Plasma::ServiceJob *updateJob = gtfsService->startOperationCall( serviceMap ); connect( updateJob, SIGNAL(finished(KJob*)), gtfsService, SLOT(deleteLater()) ); } void ServiceProviderDataWidget::deletionFinished( KJob *job ) { if ( job->error() != 0 ) { KMessageBox::information( this, i18nc("@info", "Deleting the GTFS database failed: " "%1", job->errorString()) ); } } void ServiceProviderDataDialog::gtfsDatabaseDeletionFinished() { // Disable "Delete GTFS database" button enableButton( KDialog::User2, false ); } } // namespace Timetable diff --git a/libpublictransporthelper/stoplineedit.cpp b/libpublictransporthelper/stoplineedit.cpp index 0f9e754..4ca341e 100644 --- a/libpublictransporthelper/stoplineedit.cpp +++ b/libpublictransporthelper/stoplineedit.cpp @@ -1,1084 +1,1085 @@ /* * Copyright 2012 Friedrich Pülz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details * * You should have received a copy of the GNU Library 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. */ // Own includes #include "stoplineedit.h" #include "stopsettings.h" #ifdef MARBLE_FOUND #include "publictransportmapwidget.h" #include "publictransportlayer.h" #include "popuphandler.h" #endif // Plasma/KDE includes #include #include #include #include #include #include #include #include // Qt includes #include #include #include #include #include #include +#include #include #include /** @brief Namespace for the publictransport helper library. */ namespace PublicTransport { /// Private class of StopLineEdit class StopLineEditPrivate { Q_DECLARE_PUBLIC( StopLineEdit ) public: /// Different states of the StopLineEdit enum State { Ready, ///< Ready to get stop suggestions WaitingForImport, ///< Waiting for the first import (eg. of the associated GTFS feed). ///< Later imports are updates and can be done in the background. This StopLineEdit ///< gets put into read only mode and the progress gets visualized by a progress bar. ///< An additional cancel button is shown to cancel the import. WaitingForStopSuggestions, ///< Waiting for an answer from the accessor with stop ///< suggestions. This StopLineEdit is in read write mode and is enabled. ///< Completions are added when the stop suggestions arrive. AskingToImportGtfsFeed, ///< Currently showing a question whether or not to import the ///< GTFS feed. This StopLineEdit gets put into read only mode, but is enabled ///< to be able to receive events for additional buttons (in this case these are the ///< answer buttons). Pause, ///< The import is not finished but suspended. Error ///< There has been an error in the data engine / service. The error gets shown and ///< this StopLineEdit gets put into read only mode. }; /// Different button types for additional buttons enum ButtonType { StartButton = 0x01, StopButton = 0x02, PauseButton = 0x04 }; Q_DECLARE_FLAGS( ButtonTypes, ButtonType ) /// Different states for an additional button enum ButtonState { ButtonNormal = 0x00, ///< Normal state (not pressed or hovered) ButtonPressed = 0x01, ///< Button is currently pressed ButtonPressedMouseOutside = 0x02, ///< The mouse button was pressed on the button but ///< then moved outside without releasing the mouse button ButtonHovered = 0x04 ///< The mouse is currently over the button. If another button ///< currently has state ButtonPressedMouseOutside only that button may get hovered. }; Q_DECLARE_FLAGS( ButtonStates, ButtonState ) /// Provides information about an additional button to be shown inside the StopLineEdit struct Button { ButtonType type; ButtonStates state; QRect rect; QIcon icon; QString toolTip; Button( ButtonType type, const QIcon &icon, const QRect &rect, const QString &tooltip = QString() ) : type(type), state(ButtonNormal), rect(rect), icon(icon), toolTip(tooltip) { }; }; StopLineEditPrivate( const QString &serviceProvider, StopLineEdit *q ) : importJob(0), q_ptr(q) { state = Ready; progress = 0; // Load data engine Plasma::PluginLoader::self()->loadDataEngine("publictransport"); this->serviceProvider = serviceProvider; }; ~StopLineEditPrivate() { Q_Q( StopLineEdit ); Plasma::DataEngineConsumer *consumer; #ifdef MARBLE_FOUND delete mapPopup; #endif // Disconnect sources to prevent warnings (No such slot QObject::dataUpdated...) Plasma::DataEngine *engine = consumer->dataEngine("publictransport"); if ( !sourceName.isEmpty() ) { engine->disconnectSource( sourceName, q ); sourceName.clear(); } if ( !serviceProvider.isEmpty() ) { engine->disconnectSource( "ServiceProvider " + serviceProvider, q ); } consumer->~DataEngineConsumer(); }; /// Get the additional button at the given @p point. The index of the button gets stored in /// @p index, if it is not null. Button *buttonAt( const QPoint &point, int *index = 0 ) { for ( int i = 0; i < buttons.count(); ++i ) { if ( buttons[i].rect.contains(point) ) { if ( index ) { *index = i; } return &buttons[i]; } } if ( index ) { *index = -1; } return 0; }; /// Get the additional button that is currently hovered or 0, if no button is hovered. /// The index of the button gets stored in @p index, if it is not null. Button *hoveredButton( int *index = 0 ) { for ( int i = 0; i < buttons.count(); ++i ) { if ( buttons[i].state.testFlag(ButtonHovered) ) { if ( index ) { *index = i; } return &buttons[i]; } } if ( index ) { *index = -1; } return 0; }; /// Add the buttons set in @p newButtons. /// @note Before adding the buttons all previous buttons are removed. void addButtons( ButtonTypes newButtons ) { // Buttons get placed into the StopLineEdit from right to left. // That means that the first button added to buttons, gets placed at the right. buttons.clear(); if ( newButtons.testFlag(StopButton) ) { Button stopButton( StopButton, QIcon::fromTheme("media-playback-stop"), QRect(), i18nc("@info:tooltip", "Stop import" "Click to cancel the currently running import of the GTFS feed. " "You won't be able to use the service provider without completing the " "import. The import can be started again later, but it will start at " "the beginning.") ); buttons << stopButton; } if ( newButtons.testFlag(PauseButton) ) { Button pauseButton( PauseButton, QIcon::fromTheme("media-playback-pause"), QRect(), i18nc("@info:tooltip", "Pause/Continue import" "Click to interrupt import. Click again to continue.") ); buttons << pauseButton; } if ( newButtons.testFlag(StartButton) ) { Button startButton( StartButton, QIcon::fromTheme("media-playback-start"), QRect(), i18nc("@info:tooltip", "Start GTFS feed import" "Click here to download the GTFS feed and import it into the " "database.") ); buttons << startButton; } }; /// Called on resize to update the positions of the additional buttons. void updateButtonRects( const QRect &contentsRect ) { const int buttonPadding = 4; const QSize buttonSize( 16, 16 ); const int buttonTop = contentsRect.top() + (contentsRect.height() - buttonSize.height()) / 2; int lastButtonLeft = contentsRect.right(); for ( int i = 0; i < buttons.count(); ++i ) { const QRect rect( QPoint(lastButtonLeft - buttonPadding - buttonSize.width(), buttonTop), buttonSize ); buttons[i].rect = rect; lastButtonLeft = rect.left(); } }; /// Draws the additional buttons and returns the horizontal space used. int drawAdditionalButtons( QPainter *painter ) { int buttonsWidth = buttons.isEmpty() ? 0 : 4; foreach ( const StopLineEditPrivate::Button &button, buttons ) { painter->drawPixmap( button.state.testFlag(StopLineEditPrivate::ButtonPressed) ? button.rect.adjusted(1, 1, 1, 1) : button.rect, button.icon.pixmap(button.rect.size(), button.state.testFlag(StopLineEditPrivate::ButtonHovered) ? QIcon::Active : QIcon::Normal) ); buttonsWidth += 4 + button.rect.width(); } return buttonsWidth; }; void connectStopsSource( const QString &stopName ) { Q_Q( StopLineEdit ); Plasma::DataEngineConsumer *consumer; Plasma::DataEngine *engine = consumer->dataEngine("publictransport"); if ( !sourceName.isEmpty() ) { engine->disconnectSource( sourceName, q ); } state = StopLineEditPrivate::WaitingForStopSuggestions; sourceName = QString("Stops %1|stop=%2").arg( serviceProvider, stopName ); if ( !city.isEmpty() ) { // m_useSeparateCityValue ) { sourceName += QString("|city=%3").arg( city ); } engine->connectSource( sourceName, q ); }; // Get the index of the stop with the given @p stopName, -1 otherwise int stopIndexFromName( const QString &stopName ) { for ( int i = 0; i < stops.count(); ++i ) { const Stop &stop = stops[i]; if ( stop.name.compare(stopName, Qt::CaseInsensitive) == 0 ) { // Found a matching suggestion item return stop index return i; } } // No matching suggestion found return -1; }; // Require stop IDs when they are available, // ie. only use validated stop names with a corresponding ID bool requireStopId() const { return providerFeatures.contains( QLatin1String("ProvidesStopID") ); }; StopList stops; Stop selectedStop; QString city; QString serviceProvider; QString providerType; QStringList providerFeatures; State state; int progress; // Progress of the data engine in processing a task (0 .. 100) QString sourceName; // Source name used to request stop suggestions at the data engine QString errorString; QString question; QString questionToolTip; QString infoMessage; QList