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 }