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

KParts

  • kparts
browseropenorsavequestion.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2009, 2010 David Faure <faure@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU Lesser General Public License as published by
6  the Free Software Foundation; either version 2 of the License or ( at
7  your option ) version 3 or, at the discretion of KDE e.V. ( which shall
8  act as a proxy as in section 14 of the GPLv3 ), any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "browseropenorsavequestion.h"
22 #include <kdebug.h>
23 #include <kaction.h>
24 #include <kfileitemactions.h>
25 #include <kpushbutton.h>
26 #include <kmenu.h>
27 #include <ksqueezedtextlabel.h>
28 #include <knotification.h>
29 #include <kdialog.h>
30 #include <kmimetypetrader.h>
31 #include <kstandardguiitem.h>
32 #include <kguiitem.h>
33 #include <kmessagebox.h>
34 #include <kmimetype.h>
35 #include <QStyle>
36 #include <QStyleOption>
37 #include <QVBoxLayout>
38 #include <QCheckBox>
39 #include <QLabel>
40 
41 using namespace KParts;
42 Q_DECLARE_METATYPE(KService::Ptr)
43 
44 static KMimeType::Ptr fixupMimeType (const QString& mimeType, const QString& fileName)
45 {
46  KMimeType::Ptr mime = KMimeType::mimeType(mimeType, KMimeType::ResolveAliases);
47  if ((!mime || mime->isDefault()) && !fileName.isEmpty()) {
48  mime = KMimeType::findByUrl(fileName, 0, false, true);
49  }
50  return mime;
51 }
52 
53 class KParts::BrowserOpenOrSaveQuestionPrivate : public KDialog
54 {
55  Q_OBJECT
56 public:
57  // Mapping to KDialog button codes
58  static const KDialog::ButtonCode Save = KDialog::Yes;
59  static const KDialog::ButtonCode OpenDefault = KDialog::User2;
60  static const KDialog::ButtonCode OpenWith = KDialog::User1;
61  static const KDialog::ButtonCode Cancel = KDialog::Cancel;
62 
63  BrowserOpenOrSaveQuestionPrivate(QWidget* parent, const KUrl& url, const QString& mimeType)
64  : KDialog(parent), url(url), mimeType(mimeType),
65  features(0)
66  {
67  // Use askSave or askEmbedOrSave from filetypesrc
68  dontAskConfig = KSharedConfig::openConfig("filetypesrc", KConfig::NoGlobals);
69 
70  setCaption(url.host());
71  setButtons(Save | OpenDefault | OpenWith | Cancel);
72  setObjectName("questionYesNoCancel");
73  setButtonGuiItem(Save, KStandardGuiItem::saveAs());
74  setButtonGuiItem(Cancel, KStandardGuiItem::cancel());
75  setDefaultButton(Save);
76 
77  QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget());
78  mainLayout->setSpacing(KDialog::spacingHint() * 2); // provide extra spacing
79  mainLayout->setMargin(0);
80 
81  QHBoxLayout *hLayout = new QHBoxLayout();
82  hLayout->setMargin(0);
83  hLayout->setSpacing(-1); // use default spacing
84  mainLayout->addLayout(hLayout, 5);
85 
86  QLabel *iconLabel = new QLabel(mainWidget());
87  QStyleOption option;
88  option.initFrom(this);
89  KIcon icon("dialog-information");
90  iconLabel->setPixmap(icon.pixmap(style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this)));
91 
92  hLayout->addWidget(iconLabel, 0, Qt::AlignCenter);
93  hLayout->addSpacing(KDialog::spacingHint());
94 
95  QVBoxLayout* textVLayout = new QVBoxLayout;
96  questionLabel = new KSqueezedTextLabel(mainWidget());
97  textVLayout->addWidget(questionLabel);
98 
99  fileNameLabel = new QLabel(mainWidget());
100  fileNameLabel->hide();
101  textVLayout->addWidget(fileNameLabel);
102 
103  mime = fixupMimeType(mimeType, url.fileName());
104  QString mimeDescription (mimeType);
105  if (mime) {
106  // Always prefer the mime-type comment over the raw type for display
107  mimeDescription = (mime->comment().isEmpty() ? mime->name() : mime->comment());
108  }
109  mimeTypeLabel = new QLabel(mainWidget());
110  mimeTypeLabel->setText(i18nc("@label Type of file", "Type: %1", mimeDescription));
111  mimeTypeLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
112  textVLayout->addWidget(mimeTypeLabel);
113 
114  hLayout->addLayout(textVLayout,5);
115 
116  mainLayout->addStretch(15);
117  dontAskAgainCheckBox = new QCheckBox(mainWidget());
118  dontAskAgainCheckBox->setText(i18nc("@label:checkbox", "Remember action for files of this type"));
119  mainLayout->addWidget(dontAskAgainCheckBox);
120  }
121 
122  bool autoEmbedMimeType(int flags);
123 
124  int executeDialog(const QString& dontShowAgainName)
125  {
126  KConfigGroup cg(dontAskConfig, "Notification Messages"); // group name comes from KMessageBox
127  const QString dontAsk = cg.readEntry(dontShowAgainName, QString()).toLower();
128  if (dontAsk == "yes" || dontAsk == "true") {
129  return Save;
130  } else if (dontAsk == "no" || dontAsk == "false") {
131  return OpenDefault;
132  }
133 
134  KNotification::event("messageQuestion", // why does KMessageBox uses Information for questionYesNoCancel?
135  questionLabel->text(), // also include mimetype?
136  QPixmap(),
137  window());
138  const int result = exec();
139 
140  if (dontAskAgainCheckBox->isChecked()) {
141  cg.writeEntry(dontShowAgainName, result == Save);
142  cg.sync();
143  }
144  return result;
145  }
146 
147  void showService(KService::Ptr selectedService)
148  {
149  KGuiItem openItem(i18nc("@label:button", "&Open with %1", selectedService->name()), selectedService->icon());
150  setButtonGuiItem(OpenWith, openItem);
151  }
152 
153  KUrl url;
154  QString mimeType;
155  KMimeType::Ptr mime;
156  KService::Ptr selectedService;
157  KSqueezedTextLabel* questionLabel;
158  BrowserOpenOrSaveQuestion::Features features;
159  QLabel* fileNameLabel;
160  QLabel* mimeTypeLabel;
161 
162 protected:
163  virtual void slotButtonClicked(int buttonId)
164  {
165  if (buttonId != OpenDefault)
166  selectedService = 0;
167  KPushButton* button = KDialog::button(KDialog::ButtonCode(buttonId));
168  if (button && !button->menu()) {
169  done(buttonId);
170  }
171  }
172 private:
173  QCheckBox* dontAskAgainCheckBox;
174  KSharedConfig::Ptr dontAskConfig;
175 
176 public Q_SLOTS:
177  void slotAppSelected(QAction* action)
178  {
179  selectedService = action->data().value<KService::Ptr>();
180  //showService(selectedService);
181  done(OpenDefault);
182  }
183 };
184 
185 
186 BrowserOpenOrSaveQuestion::BrowserOpenOrSaveQuestion(QWidget* parent, const KUrl& url, const QString& mimeType)
187  : d(new BrowserOpenOrSaveQuestionPrivate(parent, url, mimeType))
188 {
189 }
190 
191 BrowserOpenOrSaveQuestion::~BrowserOpenOrSaveQuestion()
192 {
193  delete d;
194 }
195 
196 static KAction* createAppAction(const KService::Ptr& service, QObject* parent)
197 {
198  QString actionName(service->name().replace('&', "&&"));
199  actionName = i18nc("@action:inmenu", "Open &with %1", actionName);
200 
201  KAction *act = new KAction(parent);
202  act->setIcon(KIcon(service->icon()));
203  act->setText(actionName);
204  act->setData(QVariant::fromValue(service));
205  return act;
206 }
207 
208 BrowserOpenOrSaveQuestion::Result BrowserOpenOrSaveQuestion::askOpenOrSave()
209 {
210  d->questionLabel->setText(i18nc("@info", "Open '%1'?", d->url.pathOrUrl()));
211  d->questionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
212  d->showButton(BrowserOpenOrSaveQuestionPrivate::OpenWith, false);
213 
214  KGuiItem openWithDialogItem(i18nc("@label:button", "&Open with..."), "document-open");
215 
216  // I thought about using KFileItemActions, but we don't want a submenu, nor the slots....
217  // and we want no menu at all if there's only one offer.
218  // TODO: we probably need a setTraderConstraint(), to exclude the current application?
219  const KService::List apps = KFileItemActions::associatedApplications(QStringList() << d->mimeType,
220  QString() /* TODO trader constraint */);
221  if (apps.isEmpty()) {
222  d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenDefault, openWithDialogItem);
223  } else {
224  KService::Ptr offer = apps.first();
225  KGuiItem openItem(i18nc("@label:button", "&Open with %1", offer->name()), offer->icon());
226  d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenDefault, openItem);
227  if (d->features & ServiceSelection) {
228  // OpenDefault shall use this service
229  d->selectedService = apps.first();
230  d->showButton(BrowserOpenOrSaveQuestionPrivate::OpenWith, true);
231  KMenu* menu = new KMenu(d);
232  if (apps.count() > 1) {
233  // Provide an additional button with a menu of associated apps
234  KGuiItem openWithItem(i18nc("@label:button", "&Open with"), "document-open");
235  d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenWith, openWithItem);
236  d->setButtonMenu(BrowserOpenOrSaveQuestionPrivate::OpenWith, menu, KDialog::InstantPopup);
237  QObject::connect(menu, SIGNAL(triggered(QAction*)), d, SLOT(slotAppSelected(QAction*)));
238  for (KService::List::const_iterator it = apps.begin(); it != apps.end(); ++it) {
239  KAction* act = createAppAction(*it, d);
240  menu->addAction(act);
241  }
242  KAction* openWithDialogAction = new KAction(d);
243  openWithDialogAction->setIcon(KIcon("document-open"));
244  openWithDialogAction->setText(openWithDialogItem.text());
245  menu->addAction(openWithDialogAction);
246  } else {
247  // Only one associated app, already offered by the other menu -> add "Open With..." button
248  d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenWith, openWithDialogItem);
249  }
250  } else {
251  kDebug() << "Not using new feature ServiceSelection; port the caller to BrowserOpenOrSaveQuestion::setFeature(ServiceSelection)";
252  //kDebug() << kBacktrace();
253  }
254  }
255 
256  // KEEP IN SYNC with kdebase/runtime/keditfiletype/filetypedetails.cpp!!!
257  const QString dontAskAgain = QLatin1String("askSave") + d->mimeType;
258 
259  const int choice = d->executeDialog(dontAskAgain);
260  return choice == BrowserOpenOrSaveQuestionPrivate::Save ? Save
261  : (choice == BrowserOpenOrSaveQuestionPrivate::Cancel ? Cancel : Open);
262 }
263 
264 KService::Ptr BrowserOpenOrSaveQuestion::selectedService() const
265 {
266  return d->selectedService;
267 }
268 
269 bool BrowserOpenOrSaveQuestionPrivate::autoEmbedMimeType(int flags)
270 {
271  // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
272  // NOTE: Keep this function in sync with
273  // kdebase/runtime/keditfiletype/filetypedetails.cpp
274  // FileTypeDetails::updateAskSave()
275 
276  // Don't ask for:
277  // - html (even new tabs would ask, due to about:blank!)
278  // - dirs obviously (though not common over HTTP :),
279  // - images (reasoning: no need to save, most of the time, because fast to see)
280  // e.g. postscript is different, because takes longer to read, so
281  // it's more likely that the user might want to save it.
282  // - multipart/* ("server push", see kmultipart)
283  // KEEP IN SYNC!!!
284  if (flags != (int)BrowserRun::AttachmentDisposition && mime && (
285  mime->is("text/html") ||
286  mime->is("application/xml") ||
287  mime->is("inode/directory") ||
288  mimeType.startsWith(QLatin1String("image")) ||
289  mime->is("multipart/x-mixed-replace") ||
290  mime->is("multipart/replace")))
291  return true;
292  return false;
293 }
294 
295 BrowserOpenOrSaveQuestion::Result BrowserOpenOrSaveQuestion::askEmbedOrSave(int flags)
296 {
297  if (d->autoEmbedMimeType(flags))
298  return Embed;
299 
300  // don't use KStandardGuiItem::open() here which has trailing ellipsis!
301  d->setButtonGuiItem(BrowserOpenOrSaveQuestionPrivate::OpenDefault, KGuiItem(i18nc("@label:button", "&Open"), "document-open"));
302  d->showButton(BrowserOpenOrSaveQuestionPrivate::OpenWith, false);
303 
304  d->questionLabel->setText(i18nc("@info", "Open '%1'?", d->url.pathOrUrl()));
305  d->questionLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
306 
307  const QString dontAskAgain = QLatin1String("askEmbedOrSave")+ d->mimeType; // KEEP IN SYNC!!!
308  // SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC SYNC
309 
310  const int choice = d->executeDialog(dontAskAgain);
311  return choice == BrowserOpenOrSaveQuestionPrivate::Save ? Save
312  : (choice == BrowserOpenOrSaveQuestionPrivate::Cancel ? Cancel : Embed);
313 }
314 
315 void BrowserOpenOrSaveQuestion::setFeatures(Features features)
316 {
317  d->features = features;
318 }
319 
320 void BrowserOpenOrSaveQuestion::setSuggestedFileName(const QString& suggestedFileName)
321 {
322  if (suggestedFileName.isEmpty()) {
323  return;
324  }
325 
326  d->fileNameLabel->setText(i18nc("@label File name", "Name: %1", suggestedFileName));
327  d->fileNameLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
328  d->fileNameLabel->setWhatsThis(i18nc("@info:whatsthis", "This is the file name suggested by the server"));
329  d->fileNameLabel->show();
330 
331  // If the current mime-type is the default mime-type, then attempt to
332  // determine the "real" mimetype from the file name.
333  KMimeType::Ptr mimePtr = fixupMimeType(d->mimeType, suggestedFileName);
334  if (mimePtr && mimePtr->name() != d->mimeType) {
335  d->mime = mimePtr;
336  d->mimeType = mimePtr->name();
337  // Always prefer the mime-type comment over the raw type for display
338  const QString mimeDescription (mimePtr->comment().isEmpty() ? mimePtr->name() : mimePtr->comment());
339  d->mimeTypeLabel->setText(i18nc("@label Type of file", "Type: %1", mimeDescription));
340  }
341 }
342 
343 #include "browseropenorsavequestion.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Fri Dec 7 2012 16:11:51 by doxygen 1.8.1 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.5 API Reference

Skip menu "kdelibs-4.8.5 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