Warning, file /office/calligra/libs/main/KoOpenPane.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 2005 Peter Simonsson <psn@linux.se>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "KoOpenPane.h"
0021 
0022 #include <QLayout>
0023 #include <QLabel>
0024 #include <QImage>
0025 #include <QPainter>
0026 #include <QPen>
0027 #include <QPixmap>
0028 #include <QSize>
0029 #include <QString>
0030 #include <QTreeWidget>
0031 #include <QTreeWidgetItem>
0032 #include <QStyledItemDelegate>
0033 #include <QLinearGradient>
0034 #include <QDragEnterEvent>
0035 #include <QDropEvent>
0036 #include <QMimeData>
0037 #include <QUrl>
0038 
0039 #include <klocalizedstring.h>
0040 #include <MainDebug.h>
0041 
0042 #include <KoFileDialog.h>
0043 #include <KoIcon.h>
0044 #include "KoTemplateTree.h"
0045 #include "KoTemplateGroup.h"
0046 #include "KoTemplate.h"
0047 #include "KoDetailsPane.h"
0048 #include "KoTemplatesPane.h"
0049 #include "KoRecentDocumentsPane.h"
0050 #include "ui_KoOpenPaneBase.h"
0051 
0052 #include <limits.h>
0053 #include <KSharedConfig>
0054 #include <KConfigGroup>
0055 
0056 class KoSectionListItem : public QTreeWidgetItem
0057 {
0058 public:
0059     KoSectionListItem(QTreeWidget* treeWidget, const QString& name, int sortWeight, int widgetIndex = -1)
0060             : QTreeWidgetItem(treeWidget, QStringList() << name), m_sortWeight(sortWeight), m_widgetIndex(widgetIndex) {
0061         Qt::ItemFlags newFlags = Qt::NoItemFlags;
0062 
0063         if(m_widgetIndex >= 0)
0064             newFlags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0065 
0066         setFlags(newFlags);
0067     }
0068 
0069     bool operator<(const QTreeWidgetItem & other) const override {
0070         const KoSectionListItem* item = dynamic_cast<const KoSectionListItem*>(&other);
0071 
0072         if (!item)
0073             return 0;
0074 
0075         return ((item->sortWeight() - sortWeight()) < 0);
0076     }
0077 
0078     int sortWeight() const {
0079         return m_sortWeight;
0080     }
0081 
0082     int widgetIndex() const {
0083         return m_widgetIndex;
0084     }
0085 
0086 private:
0087     int m_sortWeight;
0088     int m_widgetIndex;
0089 };
0090 
0091 
0092 class KoSectionListDelegate : public QStyledItemDelegate
0093 {
0094 public:
0095     KoSectionListDelegate(QObject* parent = 0) : QStyledItemDelegate(parent) { }
0096 
0097     void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
0098     {
0099         QStyledItemDelegate::paint(painter, option, index);
0100 
0101         if(!(option.state & (int)(QStyle::State_Active && QStyle::State_Enabled)))
0102         {
0103             int ypos = option.rect.y() + ((option.rect.height() - 2) / 2);
0104             QRect lineRect(option.rect.left(), ypos, option.rect.width(), 2);
0105             QLinearGradient gradient(option.rect.topLeft(), option.rect.bottomRight());
0106             gradient.setColorAt(option.direction == Qt::LeftToRight ? 0 : 1, option.palette.color(QPalette::Text));
0107             gradient.setColorAt(option.direction == Qt::LeftToRight ? 1 : 0, Qt::transparent);
0108 
0109             painter->fillRect(lineRect, gradient);
0110         }
0111     }
0112 };
0113 
0114 
0115 class KoOpenPanePrivate : public Ui_KoOpenPaneBase
0116 {
0117 public:
0118     KoOpenPanePrivate() :
0119             Ui_KoOpenPaneBase() {
0120         m_customWidgetsSeparator = 0;
0121         m_templatesSeparator = 0;
0122     }
0123 
0124     int m_freeCustomWidgetIndex;
0125     KoSectionListItem* m_customWidgetsSeparator;
0126     KoSectionListItem* m_templatesSeparator;
0127 };
0128 
0129 KoOpenPane::KoOpenPane(QWidget *parent, const QStringList& mimeFilter, const QString& templatesResourcePath)
0130         : QWidget(parent)
0131         , d(new KoOpenPanePrivate)
0132 {
0133     d->setupUi(this);
0134 
0135     m_mimeFilter = mimeFilter;
0136     d->m_openExistingButton->setText(i18n("Open Existing Document"));
0137 
0138     connect(d->m_openExistingButton, SIGNAL(clicked()),
0139             this, SLOT(openFileDialog()));
0140 
0141     KoSectionListDelegate* delegate = new KoSectionListDelegate(d->m_sectionList);
0142     d->m_sectionList->setItemDelegate(delegate);
0143 
0144     connect(d->m_sectionList, SIGNAL(itemSelectionChanged()),
0145             this, SLOT(updateSelectedWidget()));
0146     connect(d->m_sectionList, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
0147             this, SLOT(itemClicked(QTreeWidgetItem*)));
0148     connect(d->m_sectionList, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
0149             this, SLOT(itemClicked(QTreeWidgetItem*)));
0150 
0151     initRecentDocs();
0152     initTemplates(templatesResourcePath);
0153 
0154     d->m_freeCustomWidgetIndex = 4;
0155 
0156     if (!d->m_sectionList->selectedItems().isEmpty())
0157     {
0158         KoSectionListItem* selectedItem = static_cast<KoSectionListItem*>(d->m_sectionList->selectedItems().first());
0159 
0160         if (selectedItem) {
0161             d->m_widgetStack->widget(selectedItem->widgetIndex())->setFocus();
0162         }
0163     }
0164 
0165     QList<int> sizes;
0166 
0167     // Set the sizes of the details pane splitters
0168     KConfigGroup cfgGrp(KSharedConfig::openConfig(), "TemplateChooserDialog");
0169     sizes = cfgGrp.readEntry("DetailsPaneSplitterSizes", sizes);
0170 
0171     if (!sizes.isEmpty())
0172         emit splitterResized(0, sizes);
0173 
0174     connect(this, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)),
0175             this, SLOT(saveSplitterSizes(KoDetailsPane*,QList<int>)));
0176 
0177     setAcceptDrops(true);
0178 }
0179 
0180 KoOpenPane::~KoOpenPane()
0181 {
0182     if (!d->m_sectionList->selectedItems().isEmpty())
0183     {
0184         KoSectionListItem* item = dynamic_cast<KoSectionListItem*>(d->m_sectionList->selectedItems().first());
0185 
0186         if (item) {
0187             if (!qobject_cast<KoDetailsPane*>(d->m_widgetStack->widget(item->widgetIndex()))) {
0188                 KConfigGroup cfgGrp(KSharedConfig::openConfig(), "TemplateChooserDialog");
0189                 cfgGrp.writeEntry("LastReturnType", item->text(0));
0190             }
0191         }
0192     }
0193 
0194     delete d;
0195 }
0196 
0197 void KoOpenPane::openFileDialog()
0198 {
0199     KoFileDialog dialog(this, KoFileDialog::OpenFile, "OpenDocument");
0200     dialog.setCaption(i18n("Open Existing Document"));
0201     dialog.setDefaultDir(qApp->applicationName().contains("karbon")
0202                           ? QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)
0203                           : QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
0204     dialog.setMimeTypeFilters(m_mimeFilter);
0205     dialog.setHideNameFilterDetailsOption();
0206     QUrl url = QUrl::fromUserInput(dialog.filename());
0207     emit openExistingFile(url);
0208 }
0209 
0210 void KoOpenPane::initRecentDocs()
0211 {
0212     QString header = i18n("Recent Documents");
0213     KoRecentDocumentsPane* recentDocPane = new KoRecentDocumentsPane(this, header);
0214     connect(recentDocPane, SIGNAL(openUrl(QUrl)), this, SIGNAL(openExistingFile(QUrl)));
0215     QTreeWidgetItem* item = addPane(header, koIconName("document-open"), recentDocPane, 0);
0216     connect(recentDocPane, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)),
0217             this, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)));
0218     connect(this, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)),
0219             recentDocPane, SLOT(resizeSplitter(KoDetailsPane*,QList<int>)));
0220 
0221     if (KSharedConfig::openConfig()->hasGroup("RecentFiles")) {
0222         d->m_sectionList->setCurrentItem(item, 0, QItemSelectionModel::ClearAndSelect);
0223     }
0224 }
0225 
0226 void KoOpenPane::initTemplates(const QString& templatesResourcePath)
0227 {
0228     QTreeWidgetItem* selectItem = 0;
0229     QTreeWidgetItem* firstItem = 0;
0230     const int templateOffset = 1000;
0231 
0232     if (!templatesResourcePath.isEmpty()) {
0233         KoTemplateTree templateTree(templatesResourcePath, true);
0234 
0235         foreach (KoTemplateGroup *group, templateTree.groups()) {
0236             if (group->isHidden()) {
0237                 continue;
0238             }
0239 
0240             if (!d->m_templatesSeparator) {
0241                 d->m_templatesSeparator = new KoSectionListItem(d->m_sectionList, "", 999);
0242             }
0243 
0244             KoTemplatesPane* pane = new KoTemplatesPane(this, group->name(),
0245                     group, templateTree.defaultTemplate());
0246             connect(pane, SIGNAL(openUrl(QUrl)), this, SIGNAL(openTemplate(QUrl)));
0247             connect(pane, SIGNAL(alwaysUseChanged(KoTemplatesPane*,QString)),
0248                     this, SIGNAL(alwaysUseChanged(KoTemplatesPane*,QString)));
0249             connect(this, SIGNAL(alwaysUseChanged(KoTemplatesPane*,QString)),
0250                     pane, SLOT(changeAlwaysUseTemplate(KoTemplatesPane*,QString)));
0251             connect(pane, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)),
0252                     this, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)));
0253             connect(this, SIGNAL(splitterResized(KoDetailsPane*,QList<int>)),
0254                     pane, SLOT(resizeSplitter(KoDetailsPane*,QList<int>)));
0255             QTreeWidgetItem* item = addPane(group->name(), group->templates().first()->loadPicture(),
0256                                            pane, group->sortingWeight() + templateOffset);
0257 
0258             if (!firstItem) {
0259                 firstItem = item;
0260             }
0261 
0262             if (group == templateTree.defaultGroup()) {
0263                 firstItem = item;
0264             }
0265 
0266             if (pane->isSelected()) {
0267                 selectItem = item;
0268             }
0269         }
0270     } else {
0271         firstItem = d->m_sectionList->topLevelItem(0);
0272     }
0273 
0274     KConfigGroup cfgGrp(KSharedConfig::openConfig(), "TemplateChooserDialog");
0275 
0276     if (selectItem && (cfgGrp.readEntry("LastReturnType") == "Template")) {
0277         d->m_sectionList->setCurrentItem(selectItem, 0, QItemSelectionModel::ClearAndSelect);
0278     } else if (d->m_sectionList->selectedItems().isEmpty() && firstItem) {
0279         d->m_sectionList->setCurrentItem(firstItem, 0, QItemSelectionModel::ClearAndSelect);
0280     }
0281 }
0282 
0283 void KoOpenPane::dragEnterEvent(QDragEnterEvent *event)
0284 {
0285     if (event->mimeData()->hasUrls()) {
0286         event->accept();
0287     }
0288 }
0289 
0290 void KoOpenPane::dropEvent(QDropEvent *event)
0291 {
0292     if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) {
0293         // XXX: when the MVC refactoring is done, this can open a bunch of
0294         //      urls, but since the part/document combination is still 1:1
0295         //      that won't work for now.
0296         emit openExistingFile(event->mimeData()->urls().first());
0297 
0298     }
0299 }
0300 
0301 void KoOpenPane::addCustomDocumentWidget(QWidget *widget, const QString& title, const QString& icon)
0302 {
0303     Q_ASSERT(widget);
0304 
0305     if (!d->m_customWidgetsSeparator) {
0306         d->m_customWidgetsSeparator = new KoSectionListItem(d->m_sectionList, "", 3);
0307     }
0308 
0309     QString realtitle = title;
0310 
0311     if (realtitle.isEmpty())
0312         realtitle = i18n("Custom Document");
0313 
0314     QTreeWidgetItem* item = addPane(realtitle, icon, widget, d->m_freeCustomWidgetIndex);
0315     ++d->m_freeCustomWidgetIndex;
0316     KConfigGroup cfgGrp(KSharedConfig::openConfig(), "TemplateChooserDialog");
0317 
0318     QString lastActiveItem = cfgGrp.readEntry("LastReturnType");
0319     bool showCustomItemByDefault = cfgGrp.readEntry("ShowCustomDocumentWidgetByDefault", false);
0320     if (lastActiveItem == realtitle || (lastActiveItem.isEmpty() && showCustomItemByDefault)) {
0321         d->m_sectionList->setCurrentItem(item, 0, QItemSelectionModel::ClearAndSelect);
0322         KoSectionListItem* selectedItem = static_cast<KoSectionListItem*>(item);
0323         d->m_widgetStack->widget(selectedItem->widgetIndex())->setFocus();
0324     }
0325 }
0326 
0327 QTreeWidgetItem* KoOpenPane::addPane(const QString &title, const QString &iconName, QWidget *widget, int sortWeight)
0328 {
0329     if (!widget) {
0330         return 0;
0331     }
0332 
0333     int id = d->m_widgetStack->addWidget(widget);
0334     KoSectionListItem* listItem = new KoSectionListItem(d->m_sectionList, title, sortWeight, id);
0335     listItem->setIcon(0, QIcon::fromTheme(iconName));
0336 
0337     return listItem;
0338 }
0339 
0340 QTreeWidgetItem* KoOpenPane::addPane(const QString& title, const QPixmap& icon, QWidget* widget, int sortWeight)
0341 {
0342     if (!widget) {
0343         return 0;
0344     }
0345 
0346     int id = d->m_widgetStack->addWidget(widget);
0347     KoSectionListItem* listItem = new KoSectionListItem(d->m_sectionList, title, sortWeight, id);
0348 
0349     if (!icon.isNull()) {
0350         QImage image = icon.toImage();
0351 
0352         if ((image.width() > 48) || (image.height() > 48)) {
0353             image = image.scaled(48, 48, Qt::KeepAspectRatio, Qt::SmoothTransformation);
0354         }
0355 
0356         image = image.convertToFormat(QImage::Format_ARGB32);
0357         image = image.copy((image.width() - 48) / 2, (image.height() - 48) / 2, 48, 48);
0358         listItem->setIcon(0, QIcon(QPixmap::fromImage(image)));
0359     }
0360 
0361     return listItem;
0362 }
0363 
0364 void KoOpenPane::updateSelectedWidget()
0365 {
0366     if(!d->m_sectionList->selectedItems().isEmpty())
0367     {
0368         KoSectionListItem* section = dynamic_cast<KoSectionListItem*>(d->m_sectionList->selectedItems().first());
0369 
0370         if (!section)
0371             return;
0372 
0373         d->m_widgetStack->setCurrentIndex(section->widgetIndex());
0374     }
0375 }
0376 
0377 void KoOpenPane::saveSplitterSizes(KoDetailsPane* sender, const QList<int>& sizes)
0378 {
0379     Q_UNUSED(sender);
0380     KConfigGroup cfgGrp(KSharedConfig::openConfig(), "TemplateChooserDialog");
0381     cfgGrp.writeEntry("DetailsPaneSplitterSizes", sizes);
0382 }
0383 
0384 void KoOpenPane::itemClicked(QTreeWidgetItem* item)
0385 {
0386     KoSectionListItem* selectedItem = static_cast<KoSectionListItem*>(item);
0387 
0388     if (selectedItem && selectedItem->widgetIndex() >= 0) {
0389         d->m_widgetStack->widget(selectedItem->widgetIndex())->setFocus();
0390     }
0391 }