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