File indexing completed on 2024-04-14 15:17:43

0001 /*******************************************************************************************
0002     begin                : Sat Apr 26 2003
0003     copyright            : (C) 2003 by Jeroen Wijnhout (wijnhout@science.uva.nl)
0004                                2005 by Holger Danielsson (holger.danielsson@t-online.de)
0005                                2007-2019 by Michel Ludwig (michel.ludwig@kdemail.net)
0006  *******************************************************************************************/
0007 
0008 /***************************************************************************
0009  *                                                                         *
0010  *   This program is free software; you can redistribute it and/or modify  *
0011  *   it under the terms of the GNU General Public License as published by  *
0012  *   the Free Software Foundation; either version 2 of the License, or     *
0013  *   (at your option) any later version.                                   *
0014  *                                                                         *
0015  ***************************************************************************/
0016 
0017 #include "templates.h"
0018 
0019 #include <QDir>
0020 #include <QFileInfo>
0021 #include <QStringList>
0022 
0023 #include <KLocalizedString>
0024 #include <KMessageBox>
0025 #include <KProcess>
0026 #include <KShell>
0027 #include <KIO/Job>
0028 #include <KJobWidgets>
0029 #include <QTemporaryFile>
0030 
0031 #include "kileinfo.h"
0032 #include "kiledebug.h"
0033 #include "utilities.h"
0034 
0035 // 2005-08-04: dani
0036 //  - added script support to search existing class files
0037 //    (classes: Koma, Beamer, Prosper, HA-prosper)
0038 //  - sort items ('Empty Document' will always be the first entry)
0039 
0040 // 2006-30-04: tbraun
0041 //  - drag and drop makes no sense here
0042 //  - use the Select mode
0043 
0044 namespace KileTemplate {
0045 
0046 ////////////////////// Info //////////////////////
0047 
0048 Info::Info() : type(KileDocument::Undefined)
0049 {
0050 }
0051 
0052 bool Info::operator==(const Info &ti) const
0053 {
0054     return name==ti.name;
0055 }
0056 
0057 ////////////////////// Manager //////////////////////
0058 
0059 Manager::Manager(KileInfo* kileInfo, QObject* parent, const char* name) : QObject(parent), m_kileInfo(kileInfo)
0060 {
0061     setObjectName(name);
0062 }
0063 
0064 Manager::~Manager() {
0065 }
0066 
0067 bool Manager::copyAppData(const QUrl &src, const QString& subdir, const QString& fileName)
0068 {
0069     //let saveLocation find and create the appropriate place to
0070     //store the templates (usually $HOME/.kde/share/apps/kile/templates)
0071     QString dir = KileUtilities::writableLocation(QStandardPaths::AppDataLocation) + '/' + subdir;
0072 
0073     QUrl targetURL = QUrl::fromUserInput(dir);
0074     targetURL = targetURL.adjusted(QUrl::StripTrailingSlash);
0075     targetURL.setPath(targetURL.path() + '/' + fileName);
0076 
0077     //if a directory is found
0078     if (!dir.isNull()) {
0079         // create dir if not existing, needed for copyjob
0080         QDir testDir(dir);
0081         if (!testDir.exists()) {
0082             testDir.mkpath(dir);
0083         }
0084         // copy file
0085         if(src == targetURL) { // copying a file over itself
0086             return true;
0087         }
0088         KIO::FileCopyJob* copyJob = KIO::file_copy(src, targetURL, -1, KIO::Overwrite);
0089         KJobWidgets::setWindow(copyJob, m_kileInfo->mainWindow());
0090         return copyJob->exec();
0091     }
0092     else {
0093         KMessageBox::error(Q_NULLPTR, i18n("Could not find a folder to save %1 to.\nCheck whether you have a folder named \".kde\" with write permissions in your home folder.", fileName));
0094         return false;
0095     }
0096 }
0097 
0098 bool Manager::removeAppData(const QString &file) {
0099     QFileInfo fileInfo(file);
0100     if(fileInfo.exists()) {
0101         KIO::SimpleJob* deleteJob = KIO::file_delete(QUrl::fromUserInput(file));
0102         KJobWidgets::setWindow(deleteJob, m_kileInfo->mainWindow());
0103         return deleteJob->exec();
0104     }
0105     return true;
0106 }
0107 
0108 bool Manager::searchForTemplate(const QString& name, KileDocument::Type& type) const {
0109     for (KileTemplate::TemplateListConstIterator i = m_TemplateList.constBegin(); i != m_TemplateList.constEnd(); ++i)
0110     {
0111         KileTemplate::Info info = *i;
0112         if(info.name == name && info.type == type) {
0113             return true;
0114         }
0115     }
0116     return false;
0117 }
0118 
0119 bool Manager::add(const QUrl &templateSourceURL, const QString &name, const QUrl &icon) {
0120     KileDocument::Extensions *extensions = m_kileInfo->extensions();
0121     KileDocument::Type type = extensions->determineDocumentType(templateSourceURL);
0122     return add(templateSourceURL, type, name, icon);
0123 }
0124 
0125 bool Manager::add(const QUrl &templateSourceURL, KileDocument::Type type, const QString &name, const QUrl &icon) {
0126     KileDocument::Extensions *extensions = m_kileInfo->extensions();
0127     QString extension = extensions->defaultExtensionForDocumentType(type);
0128 
0129     return copyAppData(templateSourceURL, "templates", "template_" + name + extension) && copyAppData(icon, "pics", "type_" + name + extension + ".kileicon");
0130 }
0131 
0132 bool Manager::remove(Info ti) {
0133     return removeAppData(ti.path) && removeAppData(ti.icon);
0134 }
0135 
0136 void Manager::scanForTemplates() {
0137     KILE_DEBUG_MAIN << "===scanForTemplates()===================";
0138     QStringList dirs = KileUtilities::locateAll(QStandardPaths::AppDataLocation, "templates", QStandardPaths::LocateDirectory);
0139     QDir templates;
0140     KileTemplate::Info ti;
0141     KileDocument::Extensions *extensions = m_kileInfo->extensions();
0142 
0143     m_TemplateList.clear();
0144     for(QStringList::iterator i = dirs.begin(); i != dirs.end(); ++i) {
0145         templates = QDir(*i, "template_*");
0146         for (uint j = 0; j < templates.count(); ++j) {
0147             ti.path = templates.path() + '/' + templates[j];
0148             QFileInfo fileInfo(ti.path);
0149             ti.name = fileInfo.completeBaseName().mid(9); //remove "template_", do it this way to avoid problems with user input!
0150             ti.type = extensions->determineDocumentType(QUrl::fromUserInput(ti.path));
0151             ti.icon = KileUtilities::locate(QStandardPaths::AppDataLocation, "pics/type_" + ti.name + extensions->defaultExtensionForDocumentType(ti.type) + ".kileicon");
0152             if (m_TemplateList.contains(ti)) {
0153                 KILE_DEBUG_MAIN << "\tignoring: " << ti.path;
0154             }
0155             else {
0156                 m_TemplateList.append(ti);
0157                 KILE_DEBUG_MAIN << "\tadding: " << ti.name << " " << ti.path;
0158             }
0159         }
0160     }
0161 }
0162 
0163 QString Manager::defaultEmptyTemplateCaption()
0164 {
0165     return i18n("Empty File");
0166 }
0167 
0168 QString Manager::defaultEmptyLaTeXTemplateCaption()
0169 {
0170     return i18n("Empty LaTeX File");
0171 }
0172 
0173 QString Manager::defaultEmptyBibTeXTemplateCaption()
0174 {
0175     return i18n("Empty BibTeX File");
0176 }
0177 
0178 TemplateList Manager::getAllTemplates() const {
0179     return m_TemplateList;
0180 }
0181 
0182 TemplateList Manager::getTemplates(KileDocument::Type type) const {
0183     if(type == KileDocument::Undefined) {
0184         return getAllTemplates();
0185     }
0186 
0187     TemplateList toReturn;
0188     for (KileTemplate::TemplateListConstIterator i = m_TemplateList.constBegin(); i != m_TemplateList.constEnd(); ++i) {
0189         KileTemplate::Info info = *i;
0190         if(info.type == type) {
0191             toReturn.push_back(info);
0192         }
0193     }
0194     return toReturn;
0195 }
0196 
0197 }
0198 ////////////////////// TemplateItem //////////////////////
0199 
0200 // new compare function to make the "Empty (...) Document" items appear at the beginning
0201 
0202 TemplateItem::TemplateItem(QListWidget * parent, const KileTemplate::Info& info)
0203     : QListWidgetItem(QPixmap(info.icon), info.name, parent)
0204 {
0205     m_info = info;
0206 }
0207 
0208 bool TemplateItem::operator<(const QListWidgetItem &other) const
0209 {
0210     if(text() == KileTemplate::Manager::defaultEmptyTemplateCaption()) {
0211         return true;
0212     }
0213     else if(other.text() == KileTemplate::Manager::defaultEmptyTemplateCaption()) {
0214         return false;
0215     }
0216     else {
0217         return QListWidgetItem::operator<(other);
0218     }
0219 }
0220 
0221 ////////////////////// TemplateIconView //////////////////////
0222 
0223 TemplateIconView::TemplateIconView(QWidget *parent)
0224     : QListWidget(parent), m_templateManager(Q_NULLPTR), m_proc(Q_NULLPTR) {
0225     setViewMode(QListView::IconMode);
0226     setMovement(QListView::Static);
0227     setResizeMode(QListView::Adjust);
0228     setSelectionMode(QAbstractItemView::SingleSelection);
0229     setFlow(QListView::TopToBottom);
0230     setMinimumHeight(100);
0231     setIconSize(QSize(48, 48));
0232 }
0233 
0234 TemplateIconView::~TemplateIconView() {
0235 }
0236 
0237 void TemplateIconView::setTemplateManager(KileTemplate::Manager *templateManager) {
0238     m_templateManager = templateManager;
0239 }
0240 
0241 void TemplateIconView::fillWithTemplates(KileDocument::Type type) {
0242     if(!m_templateManager) {
0243         return;
0244     }
0245 
0246     clear();
0247 
0248     if(type == KileDocument::LaTeX) {
0249         searchLaTeXClassFiles();
0250     }
0251     else {
0252         addTemplateIcons(type);
0253     }
0254 }
0255 
0256 void TemplateIconView::searchLaTeXClassFiles()
0257 {
0258     if(!m_templateManager) {
0259         return;
0260     }
0261 
0262     m_output.clear();
0263 
0264     QString command = "kpsewhich -format=tex scrartcl.cls beamer.cls prosper.cls HA-prosper.sty";
0265 
0266     delete m_proc;
0267 
0268     m_proc = new KProcess(this);
0269     (*m_proc) << KShell::splitArgs(command);
0270 
0271     m_proc->setOutputChannelMode(KProcess::MergedChannels);
0272     m_proc->setReadChannel(QProcess::StandardOutput);
0273 
0274     connect(m_proc, SIGNAL(readyReadStandardOutput()), this, SLOT(slotProcessOutput()));
0275     connect(m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotProcessExited(int,QProcess::ExitStatus)));
0276     connect(m_proc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(slotProcessError()));
0277     KILE_DEBUG_MAIN << "=== NewFileWidget::searchClassFiles() ====================";
0278     KILE_DEBUG_MAIN << "\texecute: " << command;
0279     m_proc->start();
0280 }
0281 
0282 void TemplateIconView::slotProcessOutput()
0283 {
0284     QByteArray buf = m_proc->readAllStandardOutput();
0285     m_output += QString::fromLocal8Bit(buf.data(), buf.size());
0286 }
0287 
0288 void TemplateIconView::slotProcessError()
0289 {
0290     addTemplateIcons(KileDocument::LaTeX);
0291     emit classFileSearchFinished();
0292 }
0293 
0294 void TemplateIconView::slotProcessExited(int /*exitCode*/, QProcess::ExitStatus exitStatus)
0295 {
0296     if(exitStatus != QProcess::NormalExit) {
0297         m_output.clear();
0298     }
0299 
0300     addTemplateIcons(KileDocument::LaTeX);
0301     emit classFileSearchFinished();
0302 }
0303 
0304 void TemplateIconView::addTemplateIcons(KileDocument::Type type)
0305 {
0306     if(!m_templateManager) {
0307         return;
0308     }
0309 
0310     QString emptyIcon = KileUtilities::locate(QStandardPaths::AppDataLocation, "pics/" + QString(DEFAULT_EMPTY_ICON) + ".png" );
0311 
0312     KileTemplate::Info emptyDocumentInfo;
0313     emptyDocumentInfo.name = KileTemplate::Manager::defaultEmptyTemplateCaption();
0314     emptyDocumentInfo.icon = emptyIcon;
0315     emptyDocumentInfo.type = type;
0316     TemplateItem *emp = new TemplateItem(this, emptyDocumentInfo);
0317     setCurrentItem(emp);
0318 
0319     if(type == KileDocument::LaTeX) {
0320         // disable non standard templates
0321         QMap<QString,bool> map;
0322         map["Scrartcl"] = false;
0323         map["Scrbook"]  = false;
0324         map["Scrreprt"] = false;
0325         map["Scrlttr2"] = false;
0326         map["Beamer"]   = false;
0327         map["Prosper"]  = false;
0328         map["HA-prosper"] = false;
0329 
0330         // split search results and look, which class files are present
0331         QStringList list = m_output.split('\n');
0332         for(QStringList::Iterator it=list.begin(); it!=list.end(); ++it) {
0333             QString filename = QFileInfo(*it).fileName();
0334             if(filename=="scrartcl.cls") {
0335                 map["Scrartcl"] = true;
0336                 map["Scrbook"]  = true;
0337                 map["Scrreprt"] = true;
0338                 map["Scrlttr2"] = true;
0339             }
0340             else if(filename=="beamer.cls") {
0341                 map["Beamer"] = true;
0342             }
0343             else if(filename=="prosper.cls") {
0344                 map["Prosper"] = true;
0345             }
0346             else if(filename=="HA-prosper.sty") {
0347                 map["HA-prosper"] = true;
0348             }
0349         }
0350 
0351 
0352         KileTemplate::TemplateList templateList = m_templateManager->getTemplates(KileDocument::LaTeX);
0353         // insert all standard templates, all user-defined templates
0354         // and those templates, which have a present class
0355         for (KileTemplate::TemplateListIterator i=templateList.begin(); i != templateList.end(); ++i) {
0356             KileTemplate::Info info = *i;
0357             QString classname = info.name;
0358             if(!map.contains(classname) || map[classname]==true) {
0359                 new TemplateItem(this, info);
0360             }
0361         }
0362     }
0363     else {
0364         KileTemplate::TemplateList templateList = m_templateManager->getTemplates(type);
0365         for (KileTemplate::TemplateListIterator i=templateList.begin(); i != templateList.end(); ++i) {
0366             new TemplateItem(this, *i);
0367         }
0368     }
0369 
0370     // sort all items (item for 'Empty Document' will always be the first one)
0371     sortItems();
0372 }
0373