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
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.