• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.8.3 API Reference
  • KDE Home
  • Contact Us
 

KParts

browseropenorsavequestion.cpp
Go to the documentation of this file.
00001 /*
00002     Copyright (c) 2009, 2010 David Faure <faure@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or modify
00005     it under the terms of the GNU Lesser General Public License as published by
00006     the Free Software Foundation; either version 2 of the License or ( at
00007     your option ) version 3 or, at the discretion of KDE e.V. ( which shall
00008     act as a proxy as in section 14 of the GPLv3 ), any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "browseropenorsavequestion.h"
00022 #include <kdebug.h>
00023 #include <kaction.h>
00024 #include <kfileitemactions.h>
00025 #include <kpushbutton.h>
00026 #include <kmenu.h>
00027 #include <ksqueezedtextlabel.h>
00028 #include <knotification.h>
00029 #include <kdialog.h>
00030 #include <kmimetypetrader.h>
00031 #include <kstandardguiitem.h>
00032 #include <kguiitem.h>
00033 #include <kmessagebox.h>
00034 #include <kmimetype.h>
00035 #include <QStyle>
00036 #include <QStyleOption>
00037 #include <QVBoxLayout>
00038 #include <QCheckBox>
00039 #include <QLabel>
00040 
00041 using namespace KParts;
00042 Q_DECLARE_METATYPE(KService::Ptr)
00043 
00044 static KMimeType::Ptr fixupMimeType (const QString& mimeType, const QString& fileName)
00045 {
00046     KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
00047     if ((!mime || mime->isDefault()) && !fileName.isEmpty()) {
00048         mime = KMimeType::findByUrl(fileName, 0, false, true);
00049     }
00050     return mime;
00051 }
00052 
00053 class KParts::BrowserOpenOrSaveQuestionPrivate : public KDialog
00054 {
00055     Q_OBJECT
00056 public:
00057     // Mapping to KDialog button codes
00058     static const KDialog::ButtonCode Save = KDialog::Yes;
00059     static const KDialog::ButtonCode OpenDefault = KDialog::User2;
00060     static const KDialog::ButtonCode OpenWith = KDialog::User1;
00061     static const KDialog::ButtonCode Cancel = KDialog::Cancel;
00062         
00063     BrowserOpenOrSaveQuestionPrivate(QWidget* parent, const KUrl& url, const QString& mimeType)
00064         : KDialog(parent), url(url), mimeType(mimeType),
00065           features(0)
00066     {
00067         // Use askSave or askEmbedOrSave from filetypesrc
00068         dontAskConfig = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals);
00069 
00070         setCaption(url.host());
00071         setButtons(Save | OpenDefault | OpenWith | Cancel);
00072         setObjectName("questionYesNoCancel");
00073         setButtonGuiItem(Save, KStandardGuiItem::saveAs());
00074         setButtonGuiItem(Cancel, KStandardGuiItem::cancel());
00075         setDefaultButton(Save);
00076 
00077         QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget());
00078         mainLayout->setSpacing(KDialog::spacingHint() * 2); // provide extra spacing
00079         mainLayout->setMargin(0);
00080 
00081         QHBoxLayout *hLayout = new QHBoxLayout();
00082         hLayout->setMargin(0);
00083         hLayout->setSpacing(-1); // use default spacing
00084         mainLayout->addLayout(hLayout, 5);
00085 
00086         QLabel *iconLabel = new QLabel(mainWidget());
00087         QStyleOption option;
00088         option.initFrom(this);
00089         KIcon icon("dialog-information");
00090         iconLabel->setPixmap(icon.pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this)));
00091 
00092         hLayout->addWidget(iconLabel, 0, Qt::AlignCenter);
00093         hLayout->addSpacing(KDialog::spacingHint());
00094 
00095         QVBoxLayout* textVLayout = new QVBoxLayout;
00096         questionLabel = new KSqueezedTextLabel(mainWidget());
00097         textVLayout->addWidget(questionLabel);
00098 
00099         fileNameLabel = new QLabel(mainWidget());
00100         fileNameLabel->hide();
00101         textVLayout->addWidget(fileNameLabel);
00102 
00103         mime = fixupMimeType(mimeType, url.fileName());
00104         QString mimeDescription (mimeType);
00105         if (mime) {
00106             // Always prefer the mime-type comment over the raw type for display
00107             mimeDescription = (mime->comment().isEmpty() ? mime->name() : mime->comment());
00108         }
00109         mimeTypeLabel = new QLabel(mainWidget());
00110         mimeTypeLabel->setText(i18nc("@label Type of file", "Type: %1", mimeDescription));
00111         mimeTypeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
00112         textVLayout->addWidget(mimeTypeLabel);
00113 
00114         hLayout->addLayout(textVLayout,5);
00115 
00116         mainLayout->addStretch(15);
00117         dontAskAgainCheckBox = new QCheckBox(mainWidget());
00118         dontAskAgainCheckBox->setText(i18nc("@label:checkbox", "Remember action for files of this type"));
00119         mainLayout->addWidget(dontAskAgainCheckBox);
00120     }
00121 
00122     bool autoEmbedMimeType(int flags);
00123 
00124     int executeDialog(const QString& dontShowAgainName)
00125     {
00126         KConfigGroup cg(dontAskConfig, "Notification Messages"); // group name comes from KMessageBox
00127         const QString dontAsk = cg.readEntry(dontShowAgainName, QString()).toLower();
00128         if (dontAsk == "yes" || dontAsk == "true") {
00129             return Save;
00130         } else if (dontAsk == "no" || dontAsk == "false") {
00131             return OpenDefault;
00132         }
00133 
00134         KNotification::event("messageQuestion", // why does KMessageBox uses Information for questionYesNoCancel?
00135                              questionLabel->text(), // also include mimetype?
00136                              QPixmap(),
00137                              window());
00138         const int result = exec();
00139 
00140         if (dontAskAgainCheckBox->isChecked()) {
00141             cg.writeEntry(dontShowAgainName, result == Save);
00142             cg.sync();
00143         }
00144         return result;
00145     }
00146 
00147     void showService(KService::Ptr selectedService)
00148     {
00149         KGuiItem openItem(i18nc("@label:button", "&Open with %1", selectedService->name()), selectedService->icon());
00150         setButtonGuiItem(OpenWith, openItem);
00151     }
00152 
00153     KUrl url;
00154     QString mimeType;
00155     KMimeType::Ptr mime;
00156     KService::Ptr selectedService;
00157     KSqueezedTextLabel* questionLabel;
00158     BrowserOpenOrSaveQuestion::Features features;
00159     QLabel* fileNameLabel;
00160     QLabel* mimeTypeLabel;
00161 
00162 protected:
00163     virtual void slotButtonClicked(int buttonId)
00164     {
00165         if (buttonId != OpenDefault)
00166             selectedService = 0;
00167         KPushButton* button = KDialog::button(KDialog::ButtonCode(buttonId));
00168         if (button && !button->menu()) {
00169             done(buttonId);
00170         }
00171     }
00172 private:
00173     QCheckBox* dontAskAgainCheckBox;
00174     KSharedConfig::Ptr dontAskConfig;
00175 
00176 public Q_SLOTS:
00177     void slotAppSelected(QAction* action)
00178     {
00179         selectedService = action->data().value<KService::Ptr>();
00180         //showService(selectedService);
00181         done(OpenDefault);
00182     }
00183 };
00184 
00185 
00186 BrowserOpenOrSaveQuestion::BrowserOpenOrSaveQuestion(QWidget* parent, const KUrl& url, const QString& mimeType)
00187     : d(new BrowserOpenOrSaveQuestionPrivate(parent, url, mimeType))
00188 {
00189 }
00190 
00191 BrowserOpenOrSaveQuestion::~BrowserOpenOrSaveQuestion()
00192 {
00193     delete d;
00194 }
00195 
00196 static KAction* createAppAction(const KService::Ptr& service, QObject* parent)
00197 {
00198     QString actionName(service->name().replace('&', "&&"));
00199     actionName = i18nc("@action:inmenu", "Open &with %1", actionName);
00200 
00201     KAction *act = new KAction(parent);
00202     act->setIcon(KIcon(service->icon()));
00203     act->setText(actionName);
00204     act->setData(QVariant::fromValue(service));
00205     return act;
00206 }
00207 
00208 BrowserOpenOrSaveQuestion::Result BrowserOpenOrSaveQuestion::askOpenOrSave()
00209 {
00210     d->questionLabel->setText(i18nc("@info", "Open '%1'?", d->url.pathOrUrl()));
00211     d->questionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
00212     d->showButton(BrowserOpenOrSaveQuestionPrivate::OpenWith, false);
00213 
00214     KGuiItem openWithDialogItem(i18nc("@label:button", "&Open with..."), "document-open");
00215 
00216     // I thought about using KFileItemActions, but we don't want a submenu, nor the slots....
00217     // and we want no menu at all if there's only one offer.
00218     // TODO: we probably need a setTraderConstraint(), to exclude the current application?
00219     const KService::List apps = KFileItemActions::associatedApplications(QStringList() << d->mimeType,
00220                                                                          QString() /* TODO trader constraint */);
00221     if (apps.isEmpty()) {
00222         d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenDefault, openWithDialogItem);
00223     } else {
00224         KService::Ptr offer = apps.first();
00225         KGuiItem openItem(i18nc("@label:button", "&Open with %1", offer->name()), offer->icon());
00226         d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenDefault, openItem);
00227         if (d->features & ServiceSelection) {
00228             // OpenDefault shall use this service
00229             d->selectedService = apps.first();
00230             d->showButton(BrowserOpenOrSaveQuestionPrivate::OpenWith, true);
00231             KMenu* menu = new KMenu(d);
00232             if (apps.count() > 1) {
00233                 // Provide an additional button with a menu of associated apps
00234                 KGuiItem openWithItem(i18nc("@label:button", "&Open with"), "document-open");
00235                 d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenWith, openWithItem);
00236                 d->setButtonMenu(BrowserOpenOrSaveQuestionPrivate::OpenWith, menu, KDialog::InstantPopup);
00237                 QObject::connect(menu, SIGNAL(triggered(QAction*)), d, SLOT(slotAppSelected(QAction*)));
00238                 for (KService::List::const_iterator it = apps.begin(); it != apps.end(); ++it) {
00239                     KAction* act = createAppAction(*it, d);
00240                     menu->addAction(act);
00241                 }
00242                 KAction* openWithDialogAction = new KAction(d);
00243                 openWithDialogAction->setIcon(KIcon("document-open"));
00244                 openWithDialogAction->setText(openWithDialogItem.text());
00245                 menu->addAction(openWithDialogAction);
00246             } else {
00247                 // Only one associated app, already offered by the other menu -> add "Open With..." button
00248                 d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenWith, openWithDialogItem);
00249             }
00250         } else {
00251             kDebug() << "Not using new feature ServiceSelection; port the caller to BrowserOpenOrSaveQuestion::setFeature(ServiceSelection)";
00252             //kDebug() << kBacktrace();
00253         }
00254     }
00255 
00256     // KEEP IN SYNC with kdebase/runtime/keditfiletype/filetypedetails.cpp!!!
00257     const QString dontAskAgain = QLatin1String("askSave") + d->mimeType;
00258 
00259     const int choice = d->executeDialog(dontAskAgain);
00260     return choice == BrowserOpenOrSaveQuestionPrivate::Save ? Save
00261         : (choice == BrowserOpenOrSaveQuestionPrivate::Cancel ? Cancel : Open);
00262 }
00263 
00264 KService::Ptr BrowserOpenOrSaveQuestion::selectedService() const
00265 {
00266     return d->selectedService;
00267 }
00268 
00269 bool BrowserOpenOrSaveQuestionPrivate::autoEmbedMimeType(int flags)
00270 {
00271     // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
00272     // NOTE: Keep this function in sync with
00273     // kdebase/runtime/keditfiletype/filetypedetails.cpp
00274     //       FileTypeDetails::updateAskSave()
00275 
00276     // Don't ask for:
00277     // - html (even new tabs would ask, due to about:blank!)
00278     // - dirs obviously (though not common over HTTP :),
00279     // - images (reasoning: no need to save, most of the time, because fast to see)
00280     // e.g. postscript is different, because takes longer to read, so
00281     // it's more likely that the user might want to save it.
00282     // - multipart/* ("server push", see kmultipart)
00283     // KEEP IN SYNC!!!
00284     if (flags != (int)BrowserRun::AttachmentDisposition && mime && (
00285             mime->is("text/html") ||
00286             mime->is("application/xml") ||
00287             mime->is("inode/directory") ||
00288             mimeType.startsWith(QLatin1String("image")) ||
00289             mime->is("multipart/x-mixed-replace") ||
00290             mime->is("multipart/replace")))
00291         return true;
00292     return false;
00293 }
00294 
00295 BrowserOpenOrSaveQuestion::Result BrowserOpenOrSaveQuestion::askEmbedOrSave(int flags)
00296 {
00297     if (d->autoEmbedMimeType(flags))
00298         return Embed;
00299 
00300     // don't use KStandardGuiItem::open() here which has trailing ellipsis!
00301     d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenDefault, KGuiItem(i18nc("@label:button", "&Open"), "document-open"));
00302     d->showButton(BrowserOpenOrSaveQuestionPrivate::OpenWith, false);
00303 
00304     d->questionLabel->setText(i18nc("@info", "Open '%1'?", d->url.pathOrUrl()));
00305     d->questionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
00306 
00307     const QString dontAskAgain = QLatin1String("askEmbedOrSave")+ d->mimeType; // KEEP IN SYNC!!!
00308     // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
00309 
00310     const int choice = d->executeDialog(dontAskAgain);
00311     return choice == BrowserOpenOrSaveQuestionPrivate::Save ? Save
00312         : (choice == BrowserOpenOrSaveQuestionPrivate::Cancel ? Cancel : Embed);
00313 }
00314 
00315 void BrowserOpenOrSaveQuestion::setFeatures(Features features)
00316 {
00317     d->features = features;
00318 }
00319 
00320 void BrowserOpenOrSaveQuestion::setSuggestedFileName(const QString& suggestedFileName)
00321 {
00322     if (suggestedFileName.isEmpty()) {
00323         return;
00324     }
00325 
00326     d->fileNameLabel->setText(i18nc("@label File name", "Name: %1", suggestedFileName));
00327     d->fileNameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
00328     d->fileNameLabel->setWhatsThis(i18nc("@info:whatsthis", "This is the file name suggested by the server"));
00329     d->fileNameLabel->show();
00330 
00331     // If the current mime-type is the default mime-type, then attempt to
00332     // determine the "real" mimetype from the file name.
00333     KMimeType::Ptr mimePtr = fixupMimeType(d->mimeType, suggestedFileName);
00334     if (mimePtr && mimePtr->name() != d->mimeType) {
00335         d->mime = mimePtr;
00336         d->mimeType = mimePtr->name();
00337         // Always prefer the mime-type comment over the raw type for display
00338         const QString mimeDescription (mimePtr->comment().isEmpty() ? mimePtr->name() : mimePtr->comment());
00339         d->mimeTypeLabel->setText(i18nc("@label Type of file", "Type: %1", mimeDescription));
00340     }
00341 }
00342 
00343 #include "browseropenorsavequestion.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu May 10 2012 20:57:02 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KParts

Skip menu "KParts"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal