File indexing completed on 2024-03-24 16:41:38
0001 /******************************************************************************************** 0002 begin : Fri Aug 1 2003 0003 copyright : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) 0004 (C) 2007 by Holger Danielsson (holger.danielsson@versanet.de) 0005 (C) 2009-2018 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 // 2007-03-12 dani 0018 // - use KileDocument::Extensions 0019 // - allowed extensions are always defined as list, f.e.: .tex .ltx .latex 0020 0021 #include "kileproject.h" 0022 0023 #include <QStringList> 0024 #include <QFileInfo> 0025 #include <QDir> 0026 0027 #include <KLocalizedString> 0028 #include <KMessageBox> 0029 #include <KShell> 0030 #include <QUrl> 0031 0032 #include "documentinfo.h" 0033 #include "kiledebug.h" 0034 #include "kiledocmanager.h" 0035 #include "kiletoolmanager.h" 0036 #include "kileinfo.h" 0037 #include "kileextensions.h" 0038 #include "livepreview.h" 0039 #include "utilities.h" 0040 0041 /** 0042 * Since project file version 3, project files 'consist' of two files: one file named '<name>.kilepr' and 0043 * one file named '<name>.kilepr.gui' located in the '.kile' subdirectory of the project directory. 0044 * The former files contains the static structure of the project, and the later contains the current gui display settings 0045 * (like which file is open or on which line and column the cursors are). 0046 */ 0047 0048 0049 /* 0050 * KileProjectItem 0051 */ 0052 KileProjectItem::KileProjectItem(KileProject *project, const QUrl &url, int type) : 0053 m_project(project), 0054 m_url(url), 0055 m_type(type), 0056 m_docinfo(Q_NULLPTR), 0057 m_parent(Q_NULLPTR), 0058 m_child(Q_NULLPTR), 0059 m_sibling(Q_NULLPTR), 0060 m_order(-1) 0061 { 0062 m_bOpen = m_archive = true; 0063 0064 if (project) { 0065 project->add(this); 0066 } 0067 } 0068 0069 void KileProjectItem::setOrder(int i) 0070 { 0071 m_order = i; 0072 } 0073 0074 void KileProjectItem::setParent(KileProjectItem *projectItem) 0075 { 0076 m_parent = projectItem; 0077 0078 //update parent info 0079 if (m_parent) { 0080 if (m_parent->firstChild()) { 0081 //get last child 0082 KileProjectItem *sib = m_parent->firstChild(); 0083 while (sib->sibling()) { 0084 sib = sib->sibling(); 0085 } 0086 0087 sib->setSibling(this); 0088 } 0089 else { 0090 m_parent->setChild(this); 0091 } 0092 } 0093 else { 0094 setChild(0); 0095 setSibling(0); 0096 } 0097 } 0098 0099 void KileProjectItem::load() 0100 { 0101 KConfigGroup projectConfigGroup = m_project->configGroupForItem(this, KileProject::ProjectFile); 0102 KConfigGroup guiConfigGroup = m_project->configGroupForItem(this, KileProject::GUIFile); 0103 // project: archive, highlight, mode 0104 // gui: column, encoding, line, open, order 0105 setEncoding(projectConfigGroup.readEntry("encoding", QString())); 0106 setMode(projectConfigGroup.readEntry("mode", QString())); 0107 setHighlight(projectConfigGroup.readEntry("highlight", QString())); 0108 setArchive(projectConfigGroup.readEntry("archive", true)); 0109 setOpenState(guiConfigGroup.readEntry("open", true)); 0110 setOrder(guiConfigGroup.readEntry("order", -1)); 0111 } 0112 0113 void KileProjectItem::save() 0114 { 0115 KConfigGroup projectConfigGroup = m_project->configGroupForItem(this, KileProject::ProjectFile); 0116 KConfigGroup guiConfigGroup = m_project->configGroupForItem(this, KileProject::GUIFile); 0117 // project: archive, highlight, mode 0118 // gui: encoding, open, order 0119 projectConfigGroup.writeEntry("encoding", encoding()); 0120 projectConfigGroup.writeEntry("mode", mode()); 0121 projectConfigGroup.writeEntry("highlight", highlight()); 0122 projectConfigGroup.writeEntry("archive", archive()); 0123 guiConfigGroup.writeEntry("open", isOpen()); 0124 guiConfigGroup.writeEntry("order", order()); 0125 } 0126 0127 void KileProjectItem::loadDocumentAndViewSettings() 0128 { 0129 if(!m_docinfo) { 0130 return; 0131 } 0132 KTextEditor::Document *document = m_docinfo->getDocument(); 0133 if(!document) { 0134 return; 0135 } 0136 QList<KTextEditor::View*> viewList = document->views(); 0137 loadDocumentSettings(document); 0138 int i = 0; 0139 for(QList<KTextEditor::View*>::iterator it = viewList.begin(); it != viewList.end(); ++it) { 0140 loadViewSettings(*it, i); 0141 ++i; 0142 } 0143 } 0144 0145 void KileProjectItem::saveDocumentAndViewSettings() 0146 { 0147 if(!m_docinfo) { 0148 return; 0149 } 0150 KTextEditor::Document *document = m_docinfo->getDocument(); 0151 if(!document) { 0152 return; 0153 } 0154 QList<KTextEditor::View*> viewList = document->views(); 0155 saveDocumentSettings(document); 0156 int i = 0; 0157 for(QList<KTextEditor::View*>::iterator it = viewList.begin(); it != viewList.end(); ++it) { 0158 saveViewSettings(*it, i); 0159 ++i; 0160 } 0161 } 0162 0163 void KileProjectItem::loadViewSettings(KTextEditor::View *view, int viewIndex) 0164 { 0165 KConfigGroup configGroup = m_project->configGroupForItemViewSettings(this, viewIndex); 0166 view->readSessionConfig(configGroup); 0167 } 0168 0169 void KileProjectItem::saveViewSettings(KTextEditor::View *view, int viewIndex) 0170 { 0171 KConfigGroup configGroup = m_project->configGroupForItemViewSettings(this, viewIndex); 0172 view->writeSessionConfig(configGroup); 0173 } 0174 0175 void KileProjectItem::loadDocumentSettings(KTextEditor::Document *document) 0176 { 0177 KConfigGroup configGroup = m_project->configGroupForItemDocumentSettings(this); 0178 if(!configGroup.exists()) { 0179 return; 0180 } 0181 document->readSessionConfig(configGroup, QSet<QString>() << "SkipUrl"); 0182 } 0183 0184 void KileProjectItem::saveDocumentSettings(KTextEditor::Document *document) 0185 { 0186 KConfigGroup configGroup = m_project->configGroupForItemDocumentSettings(this); 0187 document->writeSessionConfig(configGroup, QSet<QString>() << "SkipUrl"); 0188 } 0189 0190 void KileProjectItem::print(int level) 0191 { 0192 QString str; 0193 str.fill('\t', level); 0194 KILE_DEBUG_MAIN << str << "+" << url().fileName(); 0195 0196 if (firstChild()) { 0197 firstChild()->print(++level); 0198 } 0199 0200 if (sibling()) { 0201 sibling()->print(level); 0202 } 0203 } 0204 0205 void KileProjectItem::allChildren(QList<KileProjectItem*> *list) const 0206 { 0207 KileProjectItem *firstChildItem = firstChild(); 0208 0209 // KILE_DEBUG_MAIN << "\tKileProjectItem::allChildren(" << list->count() << ")"; 0210 while(firstChildItem != Q_NULLPTR) { 0211 list->append(firstChildItem); 0212 // KILE_DEBUG_MAIN << "\t\tappending " << firstChildItem->url().fileName(); 0213 firstChildItem->allChildren(list); 0214 firstChildItem = firstChildItem->sibling(); 0215 } 0216 } 0217 0218 void KileProjectItem::setInfo(KileDocument::TextInfo *docinfo) 0219 { 0220 m_docinfo = docinfo; 0221 if(docinfo) 0222 { 0223 connect(docinfo,SIGNAL(urlChanged(KileDocument::Info*,QUrl)), this, SLOT(slotChangeURL(KileDocument::Info*,QUrl))); 0224 connect(docinfo,SIGNAL(depChanged()), m_project, SLOT(buildProjectTree())); 0225 } 0226 } 0227 0228 void KileProjectItem::changeURL(const QUrl &url) 0229 { 0230 // don't allow empty URLs 0231 if(!url.isEmpty() && m_url != url) 0232 { 0233 m_url = url; 0234 emit(urlChanged(this)); 0235 } 0236 } 0237 0238 void KileProjectItem::slotChangeURL(KileDocument::Info*, const QUrl &url) 0239 { 0240 changeURL(url); 0241 } 0242 0243 /* 0244 * KileProject 0245 */ 0246 0247 // for creating an empty project 0248 KileProject::KileProject(const QString& name, const QUrl &url, KileDocument::Extensions *extensions) 0249 : QObject(Q_NULLPTR), m_invalid(false), m_masterDocument(QString()), m_useMakeIndexOptions(false), 0250 m_config(Q_NULLPTR), m_guiConfig(Q_NULLPTR), m_extmanager(extensions) 0251 { 0252 m_name = name; 0253 init(url); 0254 0255 //create the project file 0256 KConfigGroup configGroup = m_config->group("General"); 0257 configGroup.writeEntry("name", m_name); 0258 configGroup.writeEntry("kileprversion", KILE_PROJECTFILE_VERSION); 0259 configGroup.writeEntry("kileversion", kileFullVersion); 0260 0261 load(); 0262 } 0263 0264 // for opening an existing project, 'load()' still has to be called separately! 0265 KileProject::KileProject(const QUrl &url, KileDocument::Extensions *extensions) 0266 : QObject(Q_NULLPTR), m_invalid(false), m_masterDocument(QString()), m_useMakeIndexOptions(false), 0267 m_config(Q_NULLPTR), m_guiConfig(Q_NULLPTR), m_extmanager(extensions) 0268 { 0269 init(url); 0270 } 0271 0272 KileProject::~KileProject() 0273 { 0274 KILE_DEBUG_MAIN << "DELETING KILEPROJECT " << m_projecturl.url(); 0275 emit(aboutToBeDestroyed(this)); 0276 delete m_guiConfig; 0277 delete m_config; 0278 0279 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0280 delete *it; 0281 } 0282 } 0283 0284 void KileProject::init(const QUrl &url) 0285 { 0286 m_projecturl = KileUtilities::canonicalUrl(url); 0287 0288 m_baseurl = m_projecturl.adjusted(QUrl::RemoveFilename); 0289 0290 KILE_DEBUG_MAIN << "KileProject m_baseurl = " << m_baseurl.toLocalFile(); 0291 0292 m_config = new KConfig(m_projecturl.toLocalFile(), KConfig::SimpleConfig); 0293 } 0294 0295 void KileProject::setLastDocument(const QUrl &url) 0296 { 0297 if (item(url) != 0) { 0298 m_lastDocument = KileUtilities::canonicalUrl(url); 0299 } 0300 } 0301 0302 void KileProject::setExtensions(KileProjectItem::Type type, const QString & ext) 0303 { 0304 if (type == KileProjectItem::ProjectFile || type >= KileProjectItem::Other) 0305 { 0306 qWarning() << "ERROR: invalid project item type:" << type; 0307 return; 0308 } 0309 0310 // first we take all standard extensions 0311 QStringList standardExtList; 0312 if(type == KileProjectItem::Source) { 0313 standardExtList = (m_extmanager->latexDocuments()).split(' '); 0314 } 0315 else if(type == KileProjectItem::Package) { 0316 standardExtList = (m_extmanager->latexPackages()).split(' '); 0317 } 0318 else if(type == KileProjectItem::Image) { 0319 standardExtList = (m_extmanager->images()).split(' '); 0320 } 0321 else if(type == KileProjectItem::Bibliography) { 0322 standardExtList = (m_extmanager->bibtex()).split(' '); 0323 } 0324 0325 // now we scan user-defined list and accept all extension, 0326 // except standard extensions of course 0327 QString userExt; 0328 if(!ext.isEmpty()) { 0329 QStringList userExtList; 0330 0331 QStringList::ConstIterator it; 0332 QStringList list = ext.split(' '); 0333 for(it = list.constBegin(); it != list.constEnd(); ++it) { 0334 // some tiny extension checks 0335 if((*it).length() < 2 || (*it)[0] != '.') { 0336 continue; 0337 } 0338 0339 // some of the old definitions are wrong, so we test them all 0340 if(type == KileProjectItem::Source || type == KileProjectItem::Package) { 0341 if(!(m_extmanager->isLatexDocument(*it) || m_extmanager->isLatexPackage(*it))) { 0342 standardExtList << (*it); 0343 userExtList << (*it); 0344 } 0345 } 0346 else if(type == KileProjectItem::Image) { 0347 if(!m_extmanager->isImage(*it)) { 0348 standardExtList << (*it); 0349 userExtList << (*it); 0350 } 0351 } 0352 else if(type == KileProjectItem::Bibliography) { 0353 if(!m_extmanager->isBibFile(*it)) { 0354 standardExtList << (*it); 0355 userExtList << (*it); 0356 } 0357 } 0358 } 0359 if(userExtList.count() > 0) { 0360 userExt = userExtList.join(" "); 0361 } 0362 } 0363 0364 // now we build a regular expression for all extensions 0365 // (used to search for a filename with a valid extension) 0366 QString pattern = standardExtList.join("|"); 0367 pattern.replace('.', "\\."); 0368 pattern = '('+ pattern +")$"; 0369 0370 // and save it 0371 m_reExtensions[type-1].setPattern(pattern); 0372 0373 // if the list of user-defined extensions has changed 0374 // we save the new value and (re)build the project tree 0375 if (m_extensions[type-1] != userExt) { 0376 m_extensions[type-1] = userExt; 0377 buildProjectTree(); 0378 } 0379 } 0380 0381 void KileProject::setDefaultGraphicExt(const QString & ext) { 0382 m_defGraphicExt = ext; 0383 } 0384 0385 const QString & KileProject::defaultGraphicExt() { 0386 return m_defGraphicExt; 0387 } 0388 0389 void KileProject::setType(KileProjectItem *projectItem) 0390 { 0391 if(projectItem->path().right(7) == ".kilepr") { 0392 projectItem->setType(KileProjectItem::ProjectFile); 0393 return; 0394 } 0395 0396 bool unknown = true; 0397 for(int i = KileProjectItem::Source; i < KileProjectItem::Other; ++i) { 0398 if(m_reExtensions[i-1].indexIn(projectItem->url().fileName()) != -1) { 0399 projectItem->setType(i); 0400 unknown = false; 0401 break; 0402 } 0403 } 0404 0405 if(unknown) { 0406 projectItem->setType(KileProjectItem::Other); 0407 } 0408 } 0409 0410 void KileProject::readMakeIndexOptions() 0411 { 0412 QString grp = KileTool::groupFor("MakeIndex", m_config); 0413 0414 //get the default value 0415 KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); 0416 KConfigGroup configGroup = cfg->group(KileTool::groupFor("MakeIndex", KileTool::configName("MakeIndex", cfg.data()))); 0417 QString deflt = configGroup.readEntry("options", "'%S'.idx"); 0418 0419 if (useMakeIndexOptions() && !grp.isEmpty()) { 0420 KConfigGroup makeIndexGroup = m_config->group(grp); 0421 QString val = makeIndexGroup.readEntry("options", deflt); 0422 if ( val.isEmpty() ) val = deflt; 0423 setMakeIndexOptions(val); 0424 } 0425 else { //use default value 0426 setMakeIndexOptions(deflt); 0427 } 0428 } 0429 0430 void KileProject::writeUseMakeIndexOptions() 0431 { 0432 if ( useMakeIndexOptions() ) 0433 KileTool::setConfigName("MakeIndex", "Default", m_config); 0434 else 0435 KileTool::setConfigName("MakeIndex", "", m_config); 0436 } 0437 0438 QString KileProject::addBaseURL(const QString &path) 0439 { 0440 KILE_DEBUG_MAIN << "===addBaseURL(const QString & " << path << " )"; 0441 if(path.isEmpty()) { 0442 return path; 0443 } 0444 0445 else if(QDir::isAbsolutePath(path)) { 0446 return KileUtilities::canonicalUrl(QUrl::fromLocalFile(path)).toLocalFile(); 0447 } 0448 else { 0449 return KileUtilities::canonicalUrl(QUrl::fromLocalFile(m_baseurl.adjusted(QUrl::StripTrailingSlash).toLocalFile() + '/' + path)).toLocalFile(); 0450 } 0451 } 0452 0453 QString KileProject::removeBaseURL(const QString &path) 0454 { 0455 if(QDir::isAbsolutePath(path)) { 0456 QFileInfo info(path); 0457 QString relPath = findRelativePath(path); 0458 KILE_DEBUG_MAIN << "removeBaseURL path is" << path << " , relPath is " << relPath; 0459 return relPath; 0460 } 0461 else { 0462 return path; 0463 } 0464 } 0465 0466 bool KileProject::appearsToBeValidProjectFile() 0467 { 0468 if(!m_config->hasGroup("General")) { 0469 return false; 0470 } 0471 0472 KConfigGroup generalGroup = m_config->group("General"); 0473 return generalGroup.hasKey("name") && generalGroup.hasKey("kileprversion") && generalGroup.hasKey("kileversion"); 0474 } 0475 0476 int KileProject::getProjectFileVersion() 0477 { 0478 KConfigGroup generalGroup = m_config->group("General"); 0479 0480 return generalGroup.readEntry("kileprversion", 0); 0481 } 0482 0483 // WARNING: before calling this method, the project file must be of the current 'kileprversion'! 0484 // also assumes that 'm_name' has been set correctly already if this is a fresh (empty) project! 0485 bool KileProject::load() 0486 { 0487 KILE_DEBUG_MAIN << "KileProject: loading..." << Qt::endl; 0488 0489 if(!ensurePrivateKileDirectoryExists(m_projecturl)) { 0490 return false; 0491 } 0492 0493 delete m_guiConfig; 0494 m_guiConfig = new KConfig(getPathForGUISettingsProjectFile(m_projecturl), KConfig::SimpleConfig); 0495 0496 //load general settings/options 0497 KConfigGroup generalGroup = m_config->group("General"); 0498 m_name = generalGroup.readEntry("name", m_name); 0499 0500 m_defGraphicExt = generalGroup.readEntry("def_graphic_ext", QString()); 0501 0502 QString master = addBaseURL(generalGroup.readEntry("masterDocument", QString())); 0503 KILE_DEBUG_MAIN << "masterDoc == " << master; 0504 setMasterDocument(master); 0505 0506 setExtensions(KileProjectItem::Source, generalGroup.readEntry("src_extensions",m_extmanager->latexDocuments())); 0507 setExtensions(KileProjectItem::Package, generalGroup.readEntry("pkg_extensions",m_extmanager->latexPackages())); 0508 setExtensions(KileProjectItem::Image, generalGroup.readEntry("img_extensions",m_extmanager->images())); 0509 setExtensions(KileProjectItem::Bibliography, generalGroup.readEntry("bib_extensions", m_extmanager->bibtex())); 0510 0511 setQuickBuildConfig(KileTool::configName("QuickBuild", m_config)); 0512 0513 if( KileTool::configName("MakeIndex",m_config).compare("Default") == 0) { 0514 setUseMakeIndexOptions(true); 0515 } 0516 else { 0517 setUseMakeIndexOptions(false); 0518 } 0519 0520 readMakeIndexOptions(); 0521 0522 QUrl projectUrl; 0523 KileProjectItem *projectItem; 0524 const QStringList groups = m_config->groupList(); 0525 0526 //retrieve all the project files and create and initialize project items for them 0527 for (const auto& group : groups) { 0528 if(!m_config->hasGroup(group)) { // 'group' might have been deleted 0529 continue; // work around bug 384039 0530 } 0531 if (group.left(5) == "item:") { 0532 QString path = group.mid(5); 0533 if (QDir::isAbsolutePath(path)) { 0534 projectUrl = QUrl::fromLocalFile(path); 0535 } 0536 else { 0537 projectUrl = m_baseurl.adjusted(QUrl::StripTrailingSlash); 0538 projectUrl.setPath(projectUrl.path() + '/' + path); 0539 } 0540 projectItem = new KileProjectItem(this, KileUtilities::canonicalUrl(projectUrl)); 0541 setType(projectItem); 0542 0543 KConfigGroup configGroup = m_config->group(group); 0544 // path has to be set before we can load it 0545 projectItem->changePath(group.mid(5)); 0546 projectItem->load(); 0547 connect(projectItem, SIGNAL(urlChanged(KileProjectItem*)), this, SLOT(itemRenamed(KileProjectItem*)) ); 0548 } 0549 } 0550 0551 // only call this after all items are created, otherwise setLastDocument doesn't accept the url 0552 KConfigGroup guiGeneralGroup = m_guiConfig->group("General"); 0553 setLastDocument(QUrl::fromLocalFile(addBaseURL(guiGeneralGroup.readEntry("lastDocument", QString())))); 0554 0555 generalGroup = m_config->group("General"); 0556 0557 readBibliographyBackendSettings(generalGroup); 0558 0559 KileTool::LivePreviewManager::readLivePreviewStatusSettings(guiGeneralGroup, this); 0560 0561 // dump(); 0562 0563 return true; 0564 } 0565 0566 bool KileProject::save() 0567 { 0568 KILE_DEBUG_MAIN << "KileProject: saving..." << Qt::endl; 0569 0570 KConfigGroup generalGroup = m_config->group("General"); 0571 KConfigGroup guiGeneralGroup = m_guiConfig->group("General"); 0572 0573 generalGroup.writeEntry("name", m_name); 0574 generalGroup.writeEntry("kileprversion", KILE_PROJECTFILE_VERSION); 0575 generalGroup.writeEntry("kileversion", kileFullVersion); 0576 generalGroup.writeEntry("def_graphic_ext", m_defGraphicExt); 0577 0578 KILE_DEBUG_MAIN << "KileProject::save() masterDoc = " << removeBaseURL(m_masterDocument); 0579 generalGroup.writeEntry("masterDocument", removeBaseURL(m_masterDocument)); 0580 guiGeneralGroup.writeEntry("lastDocument", removeBaseURL(m_lastDocument.toLocalFile())); 0581 0582 writeBibliographyBackendSettings(generalGroup); 0583 0584 KileTool::LivePreviewManager::writeLivePreviewStatusSettings(guiGeneralGroup, this); 0585 0586 writeConfigEntry("src_extensions",m_extmanager->latexDocuments(),KileProjectItem::Source); 0587 writeConfigEntry("pkg_extensions",m_extmanager->latexPackages(),KileProjectItem::Package); 0588 writeConfigEntry("img_extensions",m_extmanager->images(),KileProjectItem::Image); 0589 writeConfigEntry("bib_extensions", m_extmanager->bibtex(), KileProjectItem::Bibliography); 0590 // only to avoid problems with older versions 0591 generalGroup.writeEntry("src_extIsRegExp", false); 0592 generalGroup.writeEntry("pkg_extIsRegExp", false); 0593 generalGroup.writeEntry("img_extIsRegExp", false); 0594 0595 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0596 (*it)->save(); 0597 } 0598 0599 KileTool::setConfigName("QuickBuild", quickBuildConfig(), m_config); 0600 0601 writeUseMakeIndexOptions(); 0602 if(useMakeIndexOptions()) { 0603 QString grp = KileTool::groupFor("MakeIndex", m_config); 0604 if(grp.isEmpty()) { 0605 grp = "Default"; 0606 } 0607 KConfigGroup configGroup = m_config->group(grp); 0608 configGroup.writeEntry("options", makeIndexOptions()); 0609 } 0610 0611 m_config->sync(); 0612 m_guiConfig->sync(); 0613 0614 // dump(); 0615 0616 return true; 0617 } 0618 0619 void KileProject::writeConfigEntry(const QString &key, const QString &standardExt, KileProjectItem::Type type) 0620 { 0621 KConfigGroup generalGroup = m_config->group("General"); 0622 QString userExt = extensions(type); 0623 if(userExt.isEmpty()) { 0624 generalGroup.writeEntry(key, standardExt); 0625 } 0626 else { 0627 generalGroup.writeEntry(key, standardExt + ' ' + extensions(type)); 0628 } 0629 } 0630 0631 KConfigGroup KileProject::configGroupForItem(KileProjectItem *projectItem, ConfigScope scope) const 0632 { 0633 KConfig* cfgObject = (scope == GUIFile ? m_guiConfig : m_config); 0634 return cfgObject->group("item:" + projectItem->path()); 0635 } 0636 0637 KConfigGroup KileProject::configGroupForItemDocumentSettings(KileProjectItem *projectItem) const 0638 { 0639 return m_guiConfig->group("document-settings,item:" + projectItem->path()); 0640 } 0641 0642 KConfigGroup KileProject::configGroupForItemViewSettings(KileProjectItem *projectItem, int viewIndex) const 0643 { 0644 return m_guiConfig->group("view-settings,view=" + QString::number(viewIndex) + ",item:" + projectItem->path()); 0645 } 0646 0647 void KileProject::removeConfigGroupsForItem(KileProjectItem *projectItem) 0648 { 0649 QString itemString = "item:" + projectItem->path(); 0650 const QStringList groupList = m_config->groupList(); 0651 for (const auto& groupName : groupList) { 0652 if(!m_config->hasGroup(groupName)) { // 'groupName' might have been deleted 0653 continue; // work around bug 384039 0654 } 0655 if(groupName.indexOf(itemString) >= 0) { 0656 m_config->deleteGroup(groupName); 0657 } 0658 } 0659 } 0660 0661 static bool isAncestorOf(const KileProjectItem *toBeChecked, KileProjectItem *parent) 0662 { 0663 KileProjectItem *projectItem = parent; 0664 while(projectItem != Q_NULLPTR) { 0665 if(projectItem == toBeChecked) { 0666 return true; 0667 } 0668 projectItem = projectItem->parent(); 0669 } 0670 return false; 0671 } 0672 0673 void KileProject::buildProjectTree() 0674 { 0675 KILE_DEBUG_MAIN << "==KileProject::buildProjectTree=========================="; 0676 0677 //determine the parent doc for each item (TODO:an item can only have one parent, not necessarily true for LaTeX docs) 0678 0679 QStringList deps; 0680 QString dep; 0681 KileProjectItem *itm; 0682 0683 //clean first 0684 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0685 (*it)->setParent(0); 0686 } 0687 0688 //use the dependencies list of the documentinfo object to determine the parent 0689 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0690 //set the type correctly (changing m_extensions causes a call to buildProjectTree) 0691 setType(*it); 0692 KileDocument::Info *docinfo = (*it)->getInfo(); 0693 0694 if(docinfo) { 0695 QUrl parentUrl = docinfo->url(); 0696 if(parentUrl.isLocalFile()) { 0697 // strip the file name from 'parentUrl' 0698 parentUrl = QUrl::fromUserInput(QFileInfo(parentUrl.path()).path()); 0699 } 0700 else { 0701 parentUrl = m_baseurl; 0702 } 0703 deps = docinfo->dependencies(); 0704 for(int i = 0; i < deps.count(); ++i) { 0705 dep = deps[i]; 0706 0707 QUrl inputUrl; 0708 0709 if(m_extmanager->isTexFile(dep)) { 0710 inputUrl = QUrl::fromLocalFile(KileInfo::checkOtherPaths(parentUrl, dep, KileInfo::texinputs)); 0711 } 0712 else if(m_extmanager->isBibFile(dep)) { 0713 inputUrl = QUrl::fromLocalFile(KileInfo::checkOtherPaths(parentUrl, dep, KileInfo::bibinputs)); 0714 } 0715 itm = item(inputUrl); 0716 if(itm && (itm->parent() == 0) 0717 && !isAncestorOf(itm, *it)) { // avoid circular references if a file should 0718 // include itself in a circular way 0719 itm->setParent(*it); 0720 } 0721 } 0722 } 0723 } 0724 0725 //make a list of all the root items (items with parent == 0) 0726 m_rootItems.clear(); 0727 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0728 if((*it)->parent() == Q_NULLPTR) { 0729 m_rootItems.append(*it); 0730 } 0731 } 0732 0733 emit(projectTreeChanged(this)); 0734 } 0735 0736 KileProjectItem* KileProject::item(const QUrl &url) 0737 { 0738 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0739 if((*it)->url() == url) { 0740 return *it; 0741 } 0742 } 0743 0744 return Q_NULLPTR; 0745 } 0746 0747 KileProjectItem* KileProject::item(const KileDocument::Info *info) 0748 { 0749 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0750 KileProjectItem *current = *it; 0751 0752 if (current->getInfo() == info) { 0753 return current; 0754 } 0755 } 0756 0757 return Q_NULLPTR; 0758 } 0759 0760 void KileProject::add(KileProjectItem* projectItem) 0761 { 0762 KILE_DEBUG_MAIN << "KileProject::add projectitem" << projectItem->url().toLocalFile(); 0763 0764 setType(projectItem); 0765 0766 projectItem->changePath(findRelativePath(projectItem->url())); 0767 connect(projectItem, SIGNAL(urlChanged(KileProjectItem*)), this, SLOT(itemRenamed(KileProjectItem*)) ); 0768 0769 m_projectItems.append(projectItem); 0770 0771 emit projectItemAdded(this, projectItem); 0772 0773 // dump(); 0774 } 0775 0776 void KileProject::remove(KileProjectItem* projectItem) 0777 { 0778 KILE_DEBUG_MAIN << projectItem->path(); 0779 removeConfigGroupsForItem(projectItem); 0780 m_projectItems.removeAll(projectItem); 0781 0782 emit projectItemRemoved(this, projectItem); 0783 0784 // dump(); 0785 } 0786 0787 void KileProject::itemRenamed(KileProjectItem *projectItem) 0788 { 0789 KILE_DEBUG_MAIN << "==KileProject::itemRenamed=========================="; 0790 KILE_DEBUG_MAIN << "\t" << projectItem->url().fileName(); 0791 removeConfigGroupsForItem(projectItem); 0792 0793 projectItem->changePath(findRelativePath(projectItem->url())); 0794 } 0795 0796 QString KileProject::findRelativePath(const QString &path) 0797 { 0798 return this->findRelativePath(QUrl::fromLocalFile(path)); 0799 } 0800 0801 QString KileProject::findRelativePath(const QUrl &url) 0802 { 0803 KILE_DEBUG_MAIN << "QString KileProject::findRelativePath(const QUrl " << url.path() << ")"; 0804 0805 if ( m_baseurl.toLocalFile() == url.toLocalFile() ) { 0806 return "./"; 0807 } 0808 const QString path = QDir(m_baseurl.path()).relativeFilePath(url.path()); 0809 KILE_DEBUG_MAIN << "relPath is " << path; 0810 return path; 0811 } 0812 0813 bool KileProject::contains(const QUrl &url) 0814 { 0815 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0816 if((*it)->url() == url) { 0817 return true; 0818 } 0819 } 0820 0821 return false; 0822 } 0823 0824 bool KileProject::contains(const KileDocument::Info *info) 0825 { 0826 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0827 if((*it)->getInfo() == info) { 0828 return true; 0829 } 0830 } 0831 return false; 0832 } 0833 0834 KileProjectItem *KileProject::rootItem(KileProjectItem *projectItem) const 0835 { 0836 //find the root item (i.e. the eldest parent) 0837 KileProjectItem *root = projectItem; 0838 while(root->parent() != Q_NULLPTR) { 0839 root = root->parent(); 0840 } 0841 0842 //check if this root item is a LaTeX root 0843 if(root->getInfo()) { 0844 if (root->getInfo()->isLaTeXRoot()) { 0845 return root; 0846 } 0847 else { 0848 //if not, see if we can find another root item that is a LaTeX root 0849 for(QList<KileProjectItem*>::const_iterator it = m_rootItems.begin(); it != m_rootItems.end(); ++it) { 0850 KileProjectItem *current = *it; 0851 if(current->getInfo() && current->getInfo()->isLaTeXRoot()) { 0852 return current; 0853 } 0854 } 0855 } 0856 0857 //no LaTeX root found, return previously found root 0858 return root; 0859 } 0860 0861 //root is not a valid item (getInfo() return 0L), return original item 0862 return projectItem; 0863 } 0864 0865 void KileProject::dump() 0866 { 0867 KILE_DEBUG_MAIN << "KileProject::dump() " << m_name; 0868 for(QList<KileProjectItem*>::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0869 KileProjectItem *projectItem = *it; 0870 KILE_DEBUG_MAIN << "item " << projectItem << " has path: " << projectItem->path(); 0871 KILE_DEBUG_MAIN << "item->type() " << projectItem->type(); 0872 KILE_DEBUG_MAIN << "OpenState: " << projectItem->isOpen(); 0873 } 0874 } 0875 0876 QString KileProject::archiveFileList() const 0877 { 0878 KILE_DEBUG_MAIN << "KileProject::archiveFileList()"; 0879 0880 QString list; 0881 for(QList<KileProjectItem*>::const_iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { 0882 if ((*it)->archive()) { 0883 list.append(KShell::quoteArg((*it)->path()) + ' '); 0884 } 0885 } 0886 return list; 0887 } 0888 0889 void KileProject::setMasterDocument(const QString & master) { 0890 0891 if(!master.isEmpty()) { 0892 0893 QFileInfo fi(master); 0894 if(fi.exists()) 0895 m_masterDocument = master; 0896 else { 0897 m_masterDocument.clear(); 0898 KILE_DEBUG_MAIN << "setMasterDocument: masterDoc=Q_NULLPTR"; 0899 } 0900 0901 } 0902 else { 0903 m_masterDocument.clear(); 0904 } 0905 0906 emit (masterDocumentChanged(m_masterDocument)); 0907 } 0908 0909 namespace { 0910 0911 void moveConfigGroupKeysAsStrings(KConfig *src, KConfig *dst, const QString& groupName, const QStringList &keysToMove) 0912 { 0913 KConfigGroup srcGroup(src, groupName); 0914 KConfigGroup dstGroup(dst, groupName); 0915 0916 for(const QString& key : keysToMove) { 0917 if(srcGroup.hasKey(key)) { 0918 QString value = srcGroup.readEntry(key, QStringLiteral("")); 0919 dstGroup.writeEntry(key, value); 0920 srcGroup.deleteEntry(key); 0921 } 0922 } 0923 } 0924 0925 void deleteConfigGroupKeys(KConfig *src, const QString& groupName, const QStringList &keysToDelete) 0926 { 0927 KConfigGroup srcGroup(src, groupName); 0928 0929 for(const QString& key : keysToDelete) { 0930 srcGroup.deleteEntry(key); 0931 } 0932 } 0933 } 0934 0935 bool KileProject::migrateProjectFileToCurrentVersion() 0936 { 0937 if(getProjectFileVersion() < KILE_PROJECTFILE_VERSION) { 0938 return migrateProjectFileToVersion3(); 0939 } 0940 return true; 0941 } 0942 0943 bool KileProject::migrateProjectFileToVersion3() 0944 { 0945 KILE_DEBUG_MAIN << "Migrating project file" << m_projecturl << "to version 3"; 0946 0947 // (1) Every config group starting with "document-settings," or "view-settings," will be moved to the GUI config file 0948 // (2) In every group named "item:..." the keys "column" and "line" are deleted 0949 // (3) In every group named "item:..." the keys "open" and "order" are moved to a new group of the same name 0950 // in the GUI project file 0951 // (4) In the "General" group the keys "lastDocument", "kile_livePreviewEnabled", "kile_livePreviewStatusUserSpecified", 0952 // "kile_livePreviewTool" are moved to the "General" group in the GUI project file 0953 0954 if(!ensurePrivateKileDirectoryExists(m_projecturl)) { 0955 return false; 0956 } 0957 0958 KConfig projectGUIFile(getPathForGUISettingsProjectFile(m_projecturl), KConfig::SimpleConfig); 0959 0960 QStringList keysToMoveInItemGroups, keysToDeleteInItemGroups, keysToMoveInGeneralGroup; 0961 0962 keysToMoveInItemGroups 0963 << QStringLiteral("column") 0964 << QStringLiteral("line") 0965 << QStringLiteral("open") 0966 << QStringLiteral("order"); 0967 0968 keysToDeleteInItemGroups 0969 << QStringLiteral("column") 0970 << QStringLiteral("line"); 0971 0972 keysToMoveInGeneralGroup 0973 << QStringLiteral("lastDocument") 0974 << QStringLiteral("kile_livePreviewEnabled") 0975 << QStringLiteral("kile_livePreviewStatusUserSpecified") 0976 << QStringLiteral("kile_livePreviewTool"); 0977 0978 const QStringList groups = m_config->groupList(); 0979 for (const auto& groupName : groups) { 0980 if(!m_config->hasGroup(groupName)) { // 'groupName' might have been deleted 0981 continue; // work around bug 384039 0982 } 0983 0984 // these ones we move completely 0985 if(groupName.startsWith(QLatin1String("document-settings,")) || groupName.startsWith(QLatin1String("view-settings,"))) { 0986 KConfigGroup oldGroup(m_config, groupName); 0987 KConfigGroup guiGroup(&projectGUIFile, groupName); 0988 oldGroup.copyTo(&guiGroup); 0989 m_config->deleteGroup(groupName); 0990 continue; 0991 } 0992 0993 if(groupName.startsWith(QLatin1String("item:"))) { 0994 deleteConfigGroupKeys(m_config, groupName, keysToDeleteInItemGroups); 0995 moveConfigGroupKeysAsStrings(m_config, &projectGUIFile, groupName, keysToMoveInItemGroups); 0996 } 0997 else if(groupName == QLatin1String("General")) { 0998 moveConfigGroupKeysAsStrings(m_config, &projectGUIFile, groupName, keysToMoveInGeneralGroup); 0999 } 1000 } 1001 1002 if(!projectGUIFile.sync()) { 1003 return false; 1004 } 1005 1006 KConfigGroup configGroup = m_config->group("General"); 1007 configGroup.writeEntry("kileprversion", KILE_PROJECTFILE_VERSION); 1008 configGroup.writeEntry("kileversion", kileFullVersion); 1009 1010 return m_config->sync(); 1011 }