Warning, file /office/calligra/libs/main/KoTemplateCreateDia.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of the KDE project 0003 Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org> 0004 2000 Werner Trobin <trobin@kde.org> 0005 Copyright (C) 2004 Nicolas GOUTTE <goutte@kde.org> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include <KoTemplateCreateDia.h> 0024 0025 #include <QFile> 0026 #include <QDir> 0027 #include <QLabel> 0028 #include <QRadioButton> 0029 #include <QPushButton> 0030 #include <QCheckBox> 0031 #include <QVBoxLayout> 0032 #include <QPixmap> 0033 #include <QHBoxLayout> 0034 #include <QTreeWidget> 0035 #include <QTreeWidgetItem> 0036 #include <QGroupBox> 0037 #include <QStandardPaths> 0038 #include <QApplication> 0039 #include <QInputDialog> 0040 #include <QUrl> 0041 #include <QTemporaryFile> 0042 #include <QLineEdit> 0043 0044 #include <KoIcon.h> 0045 #include <KoDocument.h> 0046 #include <KoTemplates.h> 0047 #include <KoTemplateTree.h> 0048 #include <KoTemplateGroup.h> 0049 #include <KoTemplate.h> 0050 #include <KoResourcePaths.h> 0051 0052 #include <klocalizedstring.h> 0053 #include <kicondialog.h> 0054 #include <kmessagebox.h> 0055 #include <MainDebug.h> 0056 #include <KoNetAccess.h> 0057 #include <kiconloader.h> 0058 #include <kconfiggroup.h> 0059 #include <ksharedconfig.h> 0060 #include <kio/job.h> 0061 #include <kstandardguiitem.h> 0062 0063 // ODF thumbnail extent 0064 static const int thumbnailExtent = 128; 0065 0066 class KoTemplateCreateDiaPrivate { 0067 public: 0068 KoTemplateCreateDiaPrivate(const QString &filePath, const QPixmap &thumbnail) 0069 : m_filePath(filePath) 0070 , m_thumbnail(thumbnail) 0071 { 0072 m_tree=0; 0073 m_name=0; 0074 m_default=0; 0075 m_custom=0; 0076 m_select=0; 0077 m_preview=0; 0078 m_groups=0; 0079 m_add=0; 0080 m_remove=0; 0081 m_defaultTemplate=0; 0082 } 0083 ~KoTemplateCreateDiaPrivate() { 0084 delete m_tree; 0085 } 0086 0087 KoTemplateTree *m_tree; 0088 QLineEdit *m_name; 0089 QRadioButton *m_default, *m_custom; 0090 QPushButton *m_select; 0091 QLabel *m_preview; 0092 QString m_customFile; 0093 QPixmap m_customPixmap; 0094 QTreeWidget *m_groups; 0095 QPushButton *m_add, *m_remove; 0096 QCheckBox *m_defaultTemplate; 0097 QString m_filePath; 0098 QPixmap m_thumbnail; 0099 bool m_changed; 0100 }; 0101 0102 0103 /**************************************************************************** 0104 * 0105 * Class: koTemplateCreateDia 0106 * 0107 ****************************************************************************/ 0108 0109 KoTemplateCreateDia::KoTemplateCreateDia(const QString &templatesResourcePath, 0110 const QString &filePath, const QPixmap &thumbnail, QWidget *parent) 0111 : KoDialog(parent) 0112 , d(new KoTemplateCreateDiaPrivate(filePath, thumbnail)) 0113 { 0114 0115 setButtons( KoDialog::Ok|KoDialog::Cancel ); 0116 setDefaultButton( KoDialog::Ok ); 0117 setCaption( i18n( "Create Template" ) ); 0118 setModal( true ); 0119 setObjectName( "template create dia" ); 0120 0121 QWidget *mainwidget=mainWidget(); 0122 QHBoxLayout *mbox=new QHBoxLayout( mainwidget ); 0123 QVBoxLayout* leftbox = new QVBoxLayout(); 0124 mbox->addLayout( leftbox ); 0125 0126 QLabel *label=new QLabel(i18nc("Template name", "Name:"), mainwidget); 0127 QHBoxLayout *namefield=new QHBoxLayout(); 0128 leftbox->addLayout( namefield ); 0129 namefield->addWidget(label); 0130 d->m_name=new QLineEdit(mainwidget); 0131 d->m_name->setFocus(); 0132 connect(d->m_name, SIGNAL(textChanged(QString)), 0133 this, SLOT(slotNameChanged(QString))); 0134 namefield->addWidget(d->m_name); 0135 0136 label=new QLabel(i18n("Group:"), mainwidget); 0137 leftbox->addWidget(label); 0138 d->m_groups = new QTreeWidget(mainwidget); 0139 leftbox->addWidget(d->m_groups); 0140 d->m_groups->setColumnCount(1); 0141 d->m_groups->setHeaderHidden(true); 0142 d->m_groups->setRootIsDecorated(true); 0143 d->m_groups->setSortingEnabled(true); 0144 0145 d->m_tree = new KoTemplateTree(templatesResourcePath, true); 0146 fillGroupTree(); 0147 d->m_groups->sortItems(0, Qt::AscendingOrder); 0148 0149 QHBoxLayout *bbox=new QHBoxLayout(); 0150 leftbox->addLayout( bbox ); 0151 d->m_add=new QPushButton(i18n("&Add Group..."), mainwidget); 0152 connect(d->m_add, SIGNAL(clicked()), this, SLOT(slotAddGroup())); 0153 bbox->addWidget(d->m_add); 0154 d->m_remove=new QPushButton(i18n("&Remove"), mainwidget); 0155 connect(d->m_remove, SIGNAL(clicked()), this, SLOT(slotRemove())); 0156 bbox->addWidget(d->m_remove); 0157 0158 QVBoxLayout *rightbox=new QVBoxLayout(); 0159 mbox->addLayout( rightbox ); 0160 QGroupBox *pixbox = new QGroupBox(i18n("Picture"), mainwidget); 0161 rightbox->addWidget(pixbox); 0162 QVBoxLayout *pixlayout=new QVBoxLayout(pixbox ); 0163 d->m_default=new QRadioButton(i18n("&Preview"), pixbox); 0164 d->m_default->setChecked(true); 0165 connect(d->m_default, SIGNAL(clicked()), this, SLOT(slotDefault())); 0166 pixlayout->addWidget(d->m_default); 0167 QHBoxLayout *custombox=new QHBoxLayout(); 0168 d->m_custom=new QRadioButton(i18n("Custom:"), pixbox); 0169 d->m_custom->setChecked(false); 0170 connect(d->m_custom, SIGNAL(clicked()), this, SLOT(slotCustom())); 0171 custombox->addWidget(d->m_custom); 0172 d->m_select=new QPushButton(i18n("&Select..."), pixbox); 0173 connect(d->m_select, SIGNAL(clicked()), this, SLOT(slotSelect())); 0174 custombox->addWidget(d->m_select); 0175 custombox->addStretch(1); 0176 pixlayout->addLayout(custombox); 0177 d->m_preview=new QLabel(pixbox); // setPixmap() -> auto resize? 0178 pixlayout->addWidget(d->m_preview, 0, Qt::AlignCenter); 0179 pixlayout->addStretch(1); 0180 0181 d->m_defaultTemplate = new QCheckBox( i18n("Use the new template as default"), mainwidget ); 0182 d->m_defaultTemplate->setChecked( true ); 0183 // QT5TODO: think about restoring this 0184 // d->m_defaultTemplate->setToolTip( i18n("Use the new template every time %1 starts",componentData.aboutData()->programName() ) ); 0185 rightbox->addWidget( d->m_defaultTemplate ); 0186 0187 enableButtonOk(false); 0188 d->m_changed=false; 0189 updatePixmap(); 0190 0191 connect(d->m_groups, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged())); 0192 0193 d->m_remove->setEnabled(d->m_groups->currentItem()); 0194 connect(this,SIGNAL(okClicked()),this,SLOT(slotOk())); 0195 } 0196 0197 KoTemplateCreateDia::~KoTemplateCreateDia() { 0198 delete d; 0199 } 0200 0201 void KoTemplateCreateDia::slotSelectionChanged() 0202 { 0203 const QTreeWidgetItem* item = d->m_groups->currentItem(); 0204 d->m_remove->setEnabled( item ); 0205 if ( ! item ) 0206 return; 0207 0208 if ( item->parent() != nullptr ) 0209 { 0210 d->m_name->setText( item->text( 0 ) ); 0211 } 0212 } 0213 0214 void KoTemplateCreateDia::createTemplate(const QString &templatesResourcePath, 0215 const char *suffix, 0216 KoDocument *document, QWidget *parent) 0217 { 0218 QTemporaryFile *tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/") + qAppName() + QLatin1String("_XXXXXX") + suffix); 0219 //Check that creation of temp file was successful 0220 if (!tempFile->open()) { 0221 delete tempFile; 0222 qWarning("Creation of temporary file to store template failed."); 0223 return; 0224 } 0225 const QString fileName = tempFile->fileName(); 0226 tempFile->close(); // need to close on Windows before we can open it again to save 0227 delete tempFile; // now the file has disappeared and we can create a new file with the generated name 0228 0229 document->saveNativeFormat(fileName); 0230 0231 const QPixmap thumbnail = document->generatePreview(QSize(thumbnailExtent, thumbnailExtent)); 0232 0233 KoTemplateCreateDia *dia = new KoTemplateCreateDia(templatesResourcePath, fileName, thumbnail, parent); 0234 dia->exec(); 0235 delete dia; 0236 0237 QDir d; 0238 d.remove(fileName); 0239 } 0240 0241 static void 0242 saveAsQuadraticPng(const QPixmap &pixmap, const QString &fileName) 0243 { 0244 QImage icon = pixmap.toImage(); 0245 icon = icon.convertToFormat(QImage::Format_ARGB32); 0246 const int iconExtent = qMax(icon.width(), icon.height()); 0247 icon = icon.copy((icon.width() - iconExtent) / 2, (icon.height() - iconExtent) / 2, iconExtent, iconExtent); 0248 icon.save(fileName, "PNG"); 0249 } 0250 0251 void KoTemplateCreateDia::slotOk() { 0252 0253 // get the current item, if there is one... 0254 QTreeWidgetItem *item = d->m_groups->currentItem(); 0255 if(!item) 0256 item = d->m_groups->topLevelItem(0); 0257 if(!item) { // safe :) 0258 d->m_tree->writeTemplateTree(); 0259 slotButtonClicked( KoDialog::Cancel ); 0260 return; 0261 } 0262 // is it a group or a template? anyway - get the group :) 0263 if(item->parent() != nullptr) 0264 item=item->parent(); 0265 if(!item) { // *very* safe :P 0266 d->m_tree->writeTemplateTree(); 0267 slotButtonClicked( KoDialog::Cancel ); 0268 return; 0269 } 0270 0271 KoTemplateGroup *group=d->m_tree->find(item->text(0)); 0272 if(!group) { // even safer 0273 d->m_tree->writeTemplateTree(); 0274 slotButtonClicked( KoDialog::Cancel ); 0275 return; 0276 } 0277 0278 if(d->m_name->text().isEmpty()) { 0279 d->m_tree->writeTemplateTree(); 0280 slotButtonClicked( KoDialog::Cancel ); 0281 return; 0282 } 0283 0284 // copy the tmp file and the picture the app provides 0285 QString dir = KoResourcePaths::saveLocation("data", d->m_tree->templatesResourcePath()); 0286 dir+=group->name(); 0287 QString templateDir=dir+"/.source/"; 0288 QString iconDir=dir+"/.icon/"; 0289 0290 QString file=KoTemplates::trimmed(d->m_name->text()); 0291 QString tmpIcon=".icon/"+file; 0292 tmpIcon+=".png"; 0293 QString icon=iconDir+file; 0294 icon+=".png"; 0295 0296 // try to find the extension for the template file :P 0297 const int pos = d->m_filePath.lastIndexOf(QLatin1Char('.')); 0298 QString ext; 0299 if ( pos > -1 ) 0300 ext = d->m_filePath.mid(pos); 0301 else 0302 qWarning(/*30004*/) << "Template extension not found!"; 0303 0304 QUrl dest; 0305 dest.setPath(templateDir+file+ext); 0306 if (QFile::exists( dest.toLocalFile())) { 0307 do { 0308 file.prepend( '_' ); 0309 dest.setPath( templateDir + file + ext ); 0310 tmpIcon=".icon/"+file+".png"; 0311 icon=iconDir+file+".png"; 0312 } 0313 while ( KIO::NetAccess::exists( dest, KIO::NetAccess::DestinationSide, this ) ); 0314 } 0315 bool ignore = false; 0316 debugMain <<"Trying to create template:" << d->m_name->text() <<"URL=" <<".source/"+file+ext <<" ICON=" << tmpIcon; 0317 KoTemplate *t=new KoTemplate(d->m_name->text(), QString(), ".source/"+file+ext, tmpIcon, "", "", "", "", "", false, false, true); 0318 if(!group->add(t)) { 0319 KoTemplate *existingTemplate=group->find(d->m_name->text()); 0320 if(existingTemplate && !existingTemplate->isHidden()) { 0321 if(KMessageBox::warningYesNo(this, i18n("Do you really want to overwrite" 0322 " the existing '%1' template?",existingTemplate->name()))==KMessageBox::Yes) 0323 group->add(t, true); 0324 else 0325 { 0326 delete t; 0327 return; 0328 } 0329 } 0330 else 0331 ignore = true; 0332 } 0333 0334 QDir dummyDir; 0335 if(!dummyDir.mkpath(templateDir) || !dummyDir.mkpath(iconDir)) { 0336 d->m_tree->writeTemplateTree(); 0337 slotButtonClicked( KoDialog::Cancel ); 0338 return; 0339 } 0340 0341 QUrl orig; 0342 orig.setPath(d->m_filePath); 0343 // don't overwrite the hidden template file with a new non-hidden one 0344 if ( !ignore ) 0345 { 0346 QFile::copy(d->m_filePath, dest.path()); 0347 // save the picture as icon 0348 // (needs to be square, otherwise KIconLoader dpes nasty changes) 0349 if(d->m_default->isChecked() && !d->m_thumbnail.isNull()) { 0350 saveAsQuadraticPng(d->m_thumbnail, icon); 0351 } else if(!d->m_customPixmap.isNull()) { 0352 saveAsQuadraticPng(d->m_customPixmap, icon); 0353 } else { 0354 qWarning(/*30004*/) << "Could not save the preview picture!"; 0355 } 0356 } 0357 0358 // if there's a .directory file, we copy this one, too 0359 bool ready=false; 0360 QStringList tmp=group->dirs(); 0361 for(QStringList::ConstIterator it=tmp.constBegin(); it!=tmp.constEnd() && !ready; ++it) { 0362 if((*it).contains(dir)==0) { 0363 orig.setPath( (*it)+".directory" ); 0364 // Check if we can read the file 0365 if( KIO::NetAccess::exists(orig, KIO::NetAccess::SourceSide, this) ) { 0366 dest.setPath( dir+"/.directory" ); 0367 // We copy the file with overwrite 0368 KIO::FileCopyJob *job = KIO::file_copy( orig, dest, -1, KIO::Overwrite | KIO::HideProgressInfo); 0369 job->exec(); 0370 0371 ready=true; 0372 } 0373 } 0374 } 0375 0376 d->m_tree->writeTemplateTree(); 0377 0378 if ( d->m_defaultTemplate->isChecked() ) 0379 { 0380 0381 KConfigGroup grp(KSharedConfig::openConfig(), "TemplateChooserDialog"); 0382 grp.writeEntry( "LastReturnType", "Template" ); 0383 grp.writePathEntry( "FullTemplateName", dir + '/' + t->file() ); 0384 grp.writePathEntry( "AlwaysUseTemplate", dir + '/' + t->file() ); 0385 } 0386 } 0387 0388 void KoTemplateCreateDia::slotDefault() { 0389 0390 d->m_default->setChecked(true); 0391 d->m_custom->setChecked(false); 0392 updatePixmap(); 0393 } 0394 0395 void KoTemplateCreateDia::slotCustom() { 0396 0397 d->m_default->setChecked(false); 0398 d->m_custom->setChecked(true); 0399 if(d->m_customFile.isEmpty()) 0400 slotSelect(); 0401 else 0402 updatePixmap(); 0403 } 0404 0405 void KoTemplateCreateDia::slotSelect() { 0406 0407 d->m_default->setChecked(false); 0408 d->m_custom->setChecked(true); 0409 0410 QString name = KIconDialog::getIcon(); 0411 if( name.isEmpty() ) { 0412 if(d->m_customFile.isEmpty()) { 0413 d->m_default->setChecked(true); 0414 d->m_custom->setChecked(false); 0415 } 0416 return; 0417 } 0418 const QString path = KIconLoader::global()->iconPath(name, -thumbnailExtent); 0419 d->m_customFile = path; 0420 d->m_customPixmap=QPixmap(); 0421 updatePixmap(); 0422 } 0423 0424 void KoTemplateCreateDia::slotNameChanged(const QString &name) { 0425 0426 if( ( name.trimmed().isEmpty() || !d->m_groups->topLevelItem(0) ) && !d->m_changed ) 0427 enableButtonOk(false); 0428 else 0429 enableButtonOk(true); 0430 } 0431 0432 void KoTemplateCreateDia::slotAddGroup() { 0433 bool ok=false; 0434 const QString name = QInputDialog::getText(this, i18n("Add Group"), i18n("Enter group name:"), 0435 QLineEdit::Normal, QString(), &ok); 0436 if(!ok) 0437 return; 0438 KoTemplateGroup *group=d->m_tree->find(name); 0439 if(group && !group->isHidden()) 0440 { 0441 KMessageBox::information( this, i18n("This name is already used."), i18n("Add Group") ); 0442 return; 0443 } 0444 QString dir = KoResourcePaths::saveLocation("data", d->m_tree->templatesResourcePath()); 0445 dir+=name; 0446 KoTemplateGroup *newGroup=new KoTemplateGroup(name, dir, 0, true); 0447 d->m_tree->add(newGroup); 0448 QTreeWidgetItem *item = new QTreeWidgetItem(d->m_groups, QStringList() << name); 0449 d->m_groups->setCurrentItem(item); 0450 d->m_groups->sortItems(0, Qt::AscendingOrder); 0451 d->m_name->setFocus(); 0452 enableButtonOk(true); 0453 d->m_changed=true; 0454 } 0455 0456 void KoTemplateCreateDia::slotRemove() { 0457 0458 QTreeWidgetItem *item = d->m_groups->currentItem(); 0459 if(!item) 0460 return; 0461 0462 QString what; 0463 QString removed; 0464 if (item->parent() == nullptr) { 0465 what = i18n("Do you really want to remove that group?"); 0466 removed = i18n("Remove Group"); 0467 } else { 0468 what = i18n("Do you really want to remove that template?"); 0469 removed = i18n("Remove Template"); 0470 } 0471 0472 if(KMessageBox::warningContinueCancel(this, what, 0473 removed,KStandardGuiItem::del())==KMessageBox::Cancel) { 0474 d->m_name->setFocus(); 0475 return; 0476 } 0477 0478 if(item->parent() == nullptr) { 0479 KoTemplateGroup *group=d->m_tree->find(item->text(0)); 0480 if(group) 0481 group->setHidden(true); 0482 } 0483 else { 0484 bool done=false; 0485 QList<KoTemplateGroup*> groups = d->m_tree->groups(); 0486 QList<KoTemplateGroup*>::const_iterator it = groups.constBegin(); 0487 for(; it != groups.constEnd() && !done; ++it) { 0488 KoTemplate *t = (*it)->find(item->text(0)); 0489 0490 if(t) { 0491 t->setHidden(true); 0492 done=true; 0493 } 0494 } 0495 } 0496 delete item; 0497 item=0; 0498 enableButtonOk(true); 0499 d->m_name->setFocus(); 0500 d->m_changed=true; 0501 } 0502 0503 void KoTemplateCreateDia::updatePixmap() { 0504 0505 if(d->m_default->isChecked() && !d->m_thumbnail.isNull()) 0506 d->m_preview->setPixmap(d->m_thumbnail); 0507 else if(d->m_custom->isChecked() && !d->m_customFile.isEmpty()) { 0508 if(d->m_customPixmap.isNull()) { 0509 debugMain <<"Trying to load picture" << d->m_customFile; 0510 // use the code in KoTemplate to load the image... hacky, I know :) 0511 KoTemplate t("foo", "bar", QString(), d->m_customFile); 0512 d->m_customPixmap=t.loadPicture(); 0513 } 0514 else 0515 qWarning(/*30004*/) << "Trying to load picture"; 0516 0517 if(!d->m_customPixmap.isNull()) 0518 d->m_preview->setPixmap(d->m_customPixmap); 0519 else 0520 d->m_preview->setText(i18n("Could not load picture.")); 0521 } 0522 else 0523 d->m_preview->setText(i18n("No picture available.")); 0524 } 0525 0526 void KoTemplateCreateDia::fillGroupTree() { 0527 0528 foreach(KoTemplateGroup *group, d->m_tree->groups()) { 0529 if(group->isHidden()) 0530 continue; 0531 QTreeWidgetItem *groupItem=new QTreeWidgetItem(d->m_groups, QStringList() << group->name()); 0532 0533 foreach(KoTemplate *t, group->templates()) { 0534 if(t->isHidden()) 0535 continue; 0536 (void)new QTreeWidgetItem(groupItem, QStringList() << t->name()); 0537 } 0538 } 0539 }