diff --git a/src/kiledocmanager.cpp b/src/kiledocmanager.cpp index 9d8c5950..5e471d06 100644 --- a/src/kiledocmanager.cpp +++ b/src/kiledocmanager.cpp @@ -1,2550 +1,2552 @@ /***************************************************************************** * Copyright (C) 2004 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) * * (C) 2006-2016 by Michel Ludwig (michel.ludwig@kdemail.net) * * (C) 2007 by Holger Danielsson (holger.danielsson@versanet.de) * ******************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // 2007-03-12 dani // - use KileDocument::Extensions #include "kiledocmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dialogs/cleandialog.h" #include "dialogs/listselector.h" #include "dialogs/managetemplatesdialog.h" #include "dialogs/newfilewizard.h" #include "dialogs/projectdialogs.h" #include "documentinfo.h" #include "errorhandler.h" #include "kileconfig.h" #include "kiledebug.h" #include "kileinfo.h" #include "kileproject.h" #include "kilestdtools.h" #include "kiletool_enums.h" #include "kiletool.h" #include "kiletoolmanager.h" #include "kileviewmanager.h" #include "livepreview.h" #include "parser/parsermanager.h" #include "scriptmanager.h" #include "templates.h" #include "widgets/filebrowserwidget.h" #include "widgets/konsolewidget.h" #include "widgets/projectview.h" #include "widgets/structurewidget.h" /* * Newly created text documents have an empty URL and a non-empty document name. */ #define MAX_NUMBER_OF_STORED_SETTINGS 50 namespace KileDocument { Manager::Manager(KileInfo *info, QObject *parent, const char *name) : QObject(parent), m_ki(info), m_progressDialog(Q_NULLPTR), m_currentlySavingAll(false), m_currentlyOpeningFile(false) { setObjectName(name); m_editor = KTextEditor::Editor::instance(); if(!m_editor) { KMessageBox::error(m_ki->mainWindow(), i18n("No editor component found. Please check your KDE installation."), i18n("No editor component found.")); } } Manager::~Manager() { KILE_DEBUG_MAIN << "==KileDocument::Manager::~Manager()========="; if(m_progressDialog.isNull()) { delete m_progressDialog.data(); } } void Manager::readConfig() { } void Manager::writeConfig() { } void Manager::trashDoc(TextInfo *docinfo, KTextEditor::Document *doc /*= Q_NULLPTR */ ) { KILE_DEBUG_MAIN << "==void Manager::trashDoc(" << docinfo->url().toLocalFile() << ")====="; if(m_ki->isOpen(docinfo->url())) { return; } if(doc) { doc = docinfo->getDoc(); } //look for doc before we detach the docinfo //if we do it the other way around, docFor will always return nil if(!doc) { doc = docFor(docinfo->url()); } KILE_DEBUG_MAIN << "DETACHING " << docinfo; docinfo->detach(); KILE_DEBUG_MAIN << "\tTRASHING " << doc; if(!doc) { return; } KILE_DEBUG_MAIN << "just checking: docinfo->getDoc() = " << docinfo->getDoc(); KILE_DEBUG_MAIN << "just checking: docFor(docinfo->url()) = " << docFor(docinfo->url()); for (int i = 0; i < m_textInfoList.count(); ++i) { if((m_textInfoList.at(i) != docinfo) && (m_textInfoList.at(i)->getDoc() == doc)) { KMessageBox::information(0, i18n("The internal structure of Kile is corrupted (probably due to a bug in Kile). Please select Save All from the File menu and close Kile.\nThe Kile team apologizes for any inconvenience and would appreciate a bug report.")); qWarning() << "docinfo " << m_textInfoList.at(i) << " url " << m_textInfoList.at(i)->url().fileName() << " has a wild pointer!!!"; } } KILE_DEBUG_MAIN << "DELETING doc"; delete doc; } // update all Info's with changed user commands void Manager::updateInfos() { for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { (*it)->updateStructLevelInfo(); } } bool Manager::isOpeningFile() { return m_currentlyOpeningFile; } KTextEditor::Editor* Manager::getEditor() { return m_editor; } KTextEditor::Document* Manager::docFor(const QUrl &url) { for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { TextInfo *info = *it; if(m_ki->similarOrEqualURL(info->url(), url)) { return info->getDoc(); } } return Q_NULLPTR; } TextInfo* Manager::getInfo() const { KTextEditor::Document *doc = m_ki->activeTextDocument(); if(doc) { return textInfoFor(doc); } else { return Q_NULLPTR; } } TextInfo* Manager::textInfoFor(const QUrl &url) { if(url.isEmpty()) { return Q_NULLPTR; } KILE_DEBUG_MAIN << "==KileInfo::textInfoFor(" << url << ")=========================="; for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { TextInfo *info = *it; if (info->url() == url) { return info; } } // the URL might belong to a TextInfo* which currently doesn't have a KTextEditor::Document* // associated with it, i.e. a project item which isn't open in the editor for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProjectItem *item = (*it)->item(url); // all project items (across different projects) that share a URL have the same TextInfo*; // so, the first one we find is good enough if(item) { KileDocument::TextInfo *info = item->getInfo(); if(info) { return info; } } } KILE_DEBUG_MAIN << "\tCOULD NOT find info for " << url; return Q_NULLPTR; } TextInfo* Manager::textInfoFor(KTextEditor::Document* doc) const { if(!doc) { return Q_NULLPTR; } // TextInfo* objects that contain KTextEditor::Document* pointers must be open in the editor, i.e. // we don't have to look through the project items for(QList::const_iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { if((*it)->getDoc() == doc) { return (*it); } } KILE_DEBUG_MAIN << "\tCOULD NOT find info for" << doc->url() << "by searching via a KTextEditor::Document*"; return Q_NULLPTR; } QUrl Manager::urlFor(TextInfo* textInfo) { KileProjectItem *item = itemFor(textInfo); QUrl url; if(item) { url = item->url(); // all items with 'textInfo' share the same URL } else { KTextEditor::Document *document = textInfo->getDoc(); if(document) { url = document->url(); } } return url; } KileProject* Manager::projectForMember(const QUrl &memberUrl) { for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if(project->contains(memberUrl)) { return project; } } return Q_NULLPTR; } KileProject* Manager::projectFor(const QUrl &projecturl) { //find project with url = projecturl for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if(project->url() == projecturl) { return project; } } return Q_NULLPTR; } KileProject* Manager::projectFor(const QString &name) { //find project with url = projecturl for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if (project->name() == name) { return project; } } return Q_NULLPTR; } KileProjectItem* Manager::itemFor(const QUrl &url, KileProject *project /*=0L*/) const { if (!project) { for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; KileProjectItem *item = project->item(url); if(item) { return item; } } return Q_NULLPTR; } else { return project->item(url); } } KileProjectItem* Manager::itemFor(TextInfo *docinfo, KileProject *project /*=0*/) const { if (!project) { for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; KileProjectItem *item = project->item(docinfo); if(item) { return item; } } return Q_NULLPTR; } else { return project->item(docinfo); } } QList Manager::itemsFor(Info *docinfo) const { if(!docinfo) { return QList(); } KILE_DEBUG_MAIN << "==KileInfo::itemsFor(" << docinfo->url().fileName() << ")============"; QList list; for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; KILE_DEBUG_MAIN << "\tproject: " << (*it)->name(); if(project->contains(docinfo)) { KILE_DEBUG_MAIN << "\t\tcontains"; list.append(project->item(docinfo)); } } return list; } QList Manager::itemsFor(const QUrl &url) const { QList list; for(QList::const_iterator it = m_projects.begin(); it != m_projects.end(); ++it) { KileProject *project = *it; if(project->contains(url)) { list.append(project->item(url)); } } return list; } bool Manager::isProjectOpen() { return ( m_projects.count() > 0 ); } KileProject* Manager::activeProject() { KTextEditor::Document *doc = m_ki->activeTextDocument(); if (doc) { return projectForMember(doc->url()); } else { return Q_NULLPTR; } } KileProjectItem* Manager::activeProjectItem() { KileProject *curpr = activeProject(); KTextEditor::Document *doc = m_ki->activeTextDocument(); if (curpr && doc) { QList list = curpr->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; if (item->url() == doc->url()) { return item; } } } return Q_NULLPTR; } TextInfo* Manager::createTextDocumentInfo(KileDocument::Type type, const QUrl &url, const QUrl& baseDirectory) { TextInfo *docinfo = Q_NULLPTR; // check whether this URL belongs to an opened project and a TextInfo* object has already // been created for that URL docinfo = textInfoFor(url); if(!docinfo) { switch(type) { case Undefined: // fall through case Text: KILE_DEBUG_MAIN << "CREATING TextInfo for " << url.url(); docinfo = new TextInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->parserManager()); break; case LaTeX: KILE_DEBUG_MAIN << "CREATING LaTeXInfo for " << url.url(); docinfo = new LaTeXInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->latexCommands(), m_ki->editorExtension(), m_ki->configurationManager(), m_ki->codeCompletionManager(), m_ki->livePreviewManager(), m_ki->viewManager(), m_ki->parserManager()); break; case BibTeX: KILE_DEBUG_MAIN << "CREATING BibInfo for " << url.url(); docinfo = new BibInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->parserManager(), m_ki->latexCommands()); break; case Script: KILE_DEBUG_MAIN << "CREATING ScriptInfo for " << url.url(); docinfo = new ScriptInfo(m_ki->extensions(), m_ki->abbreviationManager(), m_ki->parserManager()); break; } docinfo->setBaseDirectory(baseDirectory); emit(documentInfoCreated(docinfo)); m_textInfoList.append(docinfo); } KILE_DEBUG_MAIN << "DOCINFO: returning " << docinfo << " " << docinfo->url().fileName(); return docinfo; } void Manager::recreateTextDocumentInfo(TextInfo *oldinfo) { QList list = itemsFor(oldinfo); QUrl url = oldinfo->url(); TextInfo *newinfo = createTextDocumentInfo(m_ki->extensions()->determineDocumentType(url), url, oldinfo->getBaseDirectory()); newinfo->setDoc(oldinfo->getDoc()); for(QList::iterator it = list.begin(); it != list.end(); ++it) { (*it)->setInfo(newinfo); } removeTextDocumentInfo(oldinfo); emit(updateStructure(false, newinfo)); } bool Manager::removeTextDocumentInfo(TextInfo *docinfo, bool closingproject /* = false */) { KILE_DEBUG_MAIN << "==Manager::removeTextDocumentInfo(Info *docinfo)====="; QList itms = itemsFor(docinfo); bool oneItem = false; if(itms.count() == 1) { oneItem = true; } if(itms.count() == 0 || ( closingproject && oneItem )) { KILE_DEBUG_MAIN << "\tremoving " << docinfo << " count = " << m_textInfoList.count(); // we still have to stop parsing for 'docinfo' QUrl url = urlFor(docinfo); if(url.isValid()) { m_ki->parserManager()->stopDocumentParsing(url); } m_textInfoList.removeAll(docinfo); emit(closingDocument(docinfo)); cleanupDocumentInfoForProjectItems(docinfo); delete docinfo; return true; } KILE_DEBUG_MAIN << "\tnot removing " << docinfo; return false; } KTextEditor::Document* Manager::createDocument(const QUrl &url, TextInfo *docinfo, const QString& encoding, const QString& mode, const QString& highlight) { KILE_DEBUG_MAIN << "==KTextEditor::Document* Manager::createDocument()==========="; KTextEditor::Document *doc = Q_NULLPTR; if(!m_editor) { return Q_NULLPTR; } doc = docFor(url); if (doc) { qWarning() << url << " already has a document!"; return doc; } doc = m_editor->createDocument(Q_NULLPTR); KILE_DEBUG_MAIN << "appending document " << doc; docinfo->setDoc(doc); // do this here to set up all the signals correctly in 'TextInfo' doc->setEncoding(encoding); KILE_DEBUG_MAIN << "url is = " << docinfo->url(); if(!url.isEmpty()) { bool r = doc->openUrl(url); // don't add scripts to the recent files if(r && docinfo->getType() != Script) { emit(addToRecentFiles(url)); } } //handle changes of the document connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SIGNAL(documentNameChanged(KTextEditor::Document*))); connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document*)), this, SIGNAL(documentUrlChanged(KTextEditor::Document*))); if(doc->metaObject()->indexOfSignal(QMetaObject::normalizedSignature("readWriteChanged(KTextEditor::Document*)")) >= 0) { // signal available in KDE 4.10 connect(doc, SIGNAL(readWriteChanged(KTextEditor::Document*)), this, SIGNAL(documentReadWriteStateChanged(KTextEditor::Document*))); } connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(newDocumentStatus(KTextEditor::Document*))); KTextEditor::ModificationInterface *modificationInterface = qobject_cast(doc); if(modificationInterface) { modificationInterface->setModifiedOnDiskWarning(true); connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SIGNAL(documentModificationStatusChanged(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason))); } if(!mode.isEmpty()){ docinfo->setMode(mode); // this ensures that mode passed with the mode parameter is actually used } if(!highlight.isEmpty()){ docinfo->setHighlightingMode(highlight); } // FIXME: the whole structure updating stuff needs to be rewritten; updates should originate from // the docinfo only, i.e. the structure view should just react to changes! connect(docinfo, SIGNAL(completed(KileDocument::Info*)), m_ki->structureWidget(), SLOT(update(KileDocument::Info*))); KILE_DEBUG_MAIN << "createDocument: url " << doc->url(); KILE_DEBUG_MAIN << "createDocument: SANITY check: " << (docinfo->getDoc() == docFor(docinfo->url())); return doc; } // WARNING: 'item' must have been set up with a TextInfo* object already KTextEditor::View* Manager::loadItem(KileDocument::Type type, KileProjectItem *item, const QString & text, bool openProjectItemViews) { KTextEditor::View *view = Q_NULLPTR; KILE_DEBUG_MAIN << "==loadItem(" << item->url() << ")======"; if(item->type() != KileProjectItem::Image) { view = loadText(type, item->url(), item->encoding(), openProjectItemViews && item->isOpen(), item->mode(), item->highlight(), text); KILE_DEBUG_MAIN << "\tloadItem: docfor = " << docFor(item->url()); TextInfo *docinfo = item->getInfo(); KILE_DEBUG_MAIN << "\tloadItem: docinfo = " << docinfo << " doc = " << docinfo->getDoc() << " docfor = " << docFor(docinfo->url()); if ( docinfo->getDoc() != docFor(docinfo->url()) ) qWarning() << "docinfo->getDoc() != docFor()"; } else { KILE_DEBUG_MAIN << "\tloadItem: no document generated"; TextInfo *docinfo = item->getInfo(); if(!docFor(item->url())) { docinfo->detach(); KILE_DEBUG_MAIN << "\t\t\tdetached"; } } return view; } KTextEditor::View* Manager::loadText(KileDocument::Type type, const QUrl &url, const QString& encoding, bool create, const QString& mode, const QString& highlight, const QString& text, int index, const QUrl &baseDirectory) { KILE_DEBUG_MAIN << "==loadText(" << url.url() << ")================="; //if doc already opened, update the structure view and return the view if(!url.isEmpty() && m_ki->isOpen(url)) { return m_ki->viewManager()->switchToTextView(url); } TextInfo *docinfo = createTextDocumentInfo(type, url, baseDirectory); KTextEditor::Document *doc = createDocument(url, docinfo, encoding, mode, highlight); m_ki->structureWidget()->clean(docinfo); if(!text.isEmpty()) { doc->setText(text); } if (doc && create) { return m_ki->viewManager()->createTextView(docinfo, index); } KILE_DEBUG_MAIN << "just after createView()"; KILE_DEBUG_MAIN << "\tdocinfo = " << docinfo << " doc = " << docinfo->getDoc() << " docfor = " << docFor(docinfo->url()); return Q_NULLPTR; } //FIXME: template stuff should be in own class KTextEditor::View* Manager::loadTemplate(TemplateItem *sel) { KILE_DEBUG_MAIN << "templateitem *sel = " << sel; QString text; if(!sel) { return Q_NULLPTR; } if (sel->name() != KileTemplate::Manager::defaultEmptyTemplateCaption() && sel->name() != KileTemplate::Manager::defaultEmptyLaTeXTemplateCaption() && sel->name() != KileTemplate::Manager::defaultEmptyBibTeXTemplateCaption()) { if(!m_editor) { return Q_NULLPTR; } //create a new document to open the template in KTextEditor::Document *tempdoc = m_editor->createDocument(Q_NULLPTR); if (!tempdoc->openUrl(QUrl::fromLocalFile(sel->path()))) { KMessageBox::error(m_ki->mainWindow(), i18n("Could not find template: %1", sel->name()), i18n("File Not Found")); } else { //substitute templates variables text = tempdoc->text(); delete tempdoc; replaceTemplateVariables(text); } } KileDocument::Type type = sel->type(); //always set the base directory for scripts return createDocumentWithText(text, type, QString(), (type == KileDocument::Script ? QUrl::fromLocalFile(m_ki->scriptManager()->getLocalScriptDirectory()) : QUrl())); } KTextEditor::View* Manager::createDocumentWithText(const QString& text, KileDocument::Type type /* = KileDocument::Undefined */, const QString& /* extension */, const QUrl &baseDirectory) { KTextEditor::View *view = loadText(type, QUrl(), QString(), true, QString(), QString(), text, -1, baseDirectory); if(view) { //FIXME this shouldn't be necessary!!! view->document()->setModified(true); newDocumentStatus(view->document()); } return view; } KTextEditor::View* Manager::createNewJScript() { KTextEditor::View *view = createDocumentWithText(QString(), Script, "js", QUrl::fromLocalFile(m_ki->scriptManager()->getLocalScriptDirectory())); emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); return view; } KTextEditor::View* Manager::createNewLaTeXDocument() { KTextEditor::View *view = createDocumentWithText(QString(), LaTeX); emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); return view; } void Manager::replaceTemplateVariables(QString &line) { line=line.replace("$$AUTHOR$$", KileConfig::author()); line=line.replace("$$DOCUMENTCLASSOPTIONS$$", KileConfig::documentClassOptions()); if (!KileConfig::templateEncoding().isEmpty()) { line=line.replace("$$INPUTENCODING$$", "\\usepackage["+ KileConfig::templateEncoding() +"]{inputenc}");} else { line = line.remove("$$INPUTENCODING$$"); } } void Manager::createTemplate() { KTextEditor::View *view = m_ki->viewManager()->currentTextView(); if (view) { if (view->document()->isModified()) { KMessageBox::information(m_ki->mainWindow(),i18n("Please save the file first.")); return; } } else { KMessageBox::information(m_ki->mainWindow(),i18n("Open/create a document first.")); return; } QUrl url = view->document()->url(); KileDocument::Type type = m_ki->extensions()->determineDocumentType(url); if(type == KileDocument::Undefined || type == KileDocument::Text) { KMessageBox::information(m_ki->mainWindow(),i18n("A template for this type of document cannot be created.")); return; } ManageTemplatesDialog mtd(m_ki->templateManager(), url, i18n("Create Template From Document")); mtd.exec(); } void Manager::removeTemplate() { ManageTemplatesDialog mtd(m_ki->templateManager(), i18n("Remove Template")); mtd.exec(); } void Manager::fileNew(KileDocument::Type type) { NewFileWizard *nfw = new NewFileWizard(m_ki->templateManager(), type, m_ki->mainWindow()); if(nfw->exec()) { KTextEditor::View *view = loadTemplate(nfw->getSelection()); if(view) { if(nfw->useWizard()) { emit(startWizard()); } emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); } } delete nfw; } void Manager::fileNewScript() { fileNew(KileDocument::Script); } void Manager::fileNew(const QUrl &url) { //create an empty file QFile file(url.toLocalFile()); file.open(QIODevice::ReadWrite); file.close(); fileOpen(url, QString()); } void Manager::fileOpen() { //determine the starting dir for the file dialog QString compileName = m_ki->getCompileName(); QString currentDir; if(QFileInfo(compileName).exists()) { currentDir = QFileInfo(compileName).absolutePath(); } else { currentDir = m_ki->fileSelector()->currentUrl().toLocalFile(); } // use a filter for fileOpen dialog Extensions *extensions = m_ki->extensions(); QString filter = extensions->fileFilterKDEStyle(true, {KileDocument::Extensions::TEX, KileDocument::Extensions::PACKAGES, KileDocument::Extensions::BIB, KileDocument::Extensions::METAPOST}); // try to get the current encoding, this is kind of ugly ... QString encoding = m_ki->toolManager()->config()->group("Kate Document Defaults").readEntry("Encoding",""); //get the URLs KEncodingFileDialog::Result result = KEncodingFileDialog::getOpenUrlsAndEncoding(encoding, QUrl::fromLocalFile(currentDir), filter, m_ki->mainWindow(), i18n("Open Files")); //open them const QList& urls = result.URLs; for (QList::ConstIterator i = urls.begin(); i != urls.end(); ++i) { const QUrl& url = *i; if(m_ki->extensions()->isProjectFile(url)) { // this can happen... (bug 317432) KILE_DEBUG_MAIN << "file is a project file:" << url; projectOpen(url); continue; } fileOpen(url, result.encoding); } } void Manager::fileSelected(const KFileItem& file) { fileSelected(file.url()); } void Manager::fileSelected(const KileProjectItem * item) { fileOpen(item->url(), item->encoding()); } void Manager::fileSelected(const QUrl &url) { fileOpen(url, QString()); } void Manager::saveURL(const QUrl &url) { KTextEditor::Document *doc = docFor(url); if(doc) { doc->save(); } } void Manager::newDocumentStatus(KTextEditor::Document *doc) { KILE_DEBUG_MAIN << "void Manager::newDocumentStatus(Kate::Document)" << endl; if(!doc) { return; } // sync terminal m_ki->texKonsole()->sync(); emit(documentModificationStatusChanged(doc, doc->isModified(), KTextEditor::ModificationInterface::OnDiskUnmodified)); } bool Manager::fileSaveAll(bool disUntitled) { // this can occur when autosaving should take place when we // are still busy with it (KIO::NetAccess keeps the event loop running) if(m_currentlySavingAll) { return true; } m_currentlySavingAll = true; KTextEditor::View *view = Q_NULLPTR; QFileInfo fi; bool oneSaveFailed = false; QUrl url, backupUrl; KILE_DEBUG_MAIN << "===Kile::fileSaveAll(disUntitled = " << disUntitled <<")"; for(int i = 0; i < m_ki->viewManager()->textViewCount(); ++i) { view = m_ki->viewManager()->textView(i); if(view && view->document()->isModified()) { url = view->document()->url(); fi.setFile(url.toLocalFile()); if(!disUntitled || !(disUntitled && url.isEmpty())) { // either we don't disregard untitled docs, or the doc has a title KILE_DEBUG_MAIN << "trying to save: " << url.toLocalFile(); bool saveResult = view->document()->documentSave(); fi.refresh(); if(!saveResult) { oneSaveFailed = true; m_ki->errorHandler()->printMessage(KileTool::Error, i18n("Kile encountered problems while saving the file %1. Do you have enough free disk space left?", url.toDisplayString()), i18n("Saving")); } } } } /* This may look superfluos but actually it is not, in the case of multiple modified docs it ensures that the structure view keeps synchronized with the currentTextView And if we only have one masterdoc or none nothing goes wrong. */ emit(updateStructure(false, Q_NULLPTR)); m_currentlySavingAll = false; return !oneSaveFailed; } TextInfo* Manager::fileOpen(const QUrl &url, const QString& encoding, int index) { m_currentlyOpeningFile = true; KILE_DEBUG_MAIN << "==Kile::fileOpen=========================="; KILE_DEBUG_MAIN << "url is " << url.url(); const QUrl realurl = symlinkFreeURL(url); KILE_DEBUG_MAIN << "symlink free url is " << realurl.url(); bool isopen = m_ki->isOpen(realurl); if(isopen) { m_currentlyOpeningFile = false; // has to be before the 'switchToTextView' call as // it emits signals that are handled by the live preview manager m_ki->viewManager()->switchToTextView(realurl); return textInfoFor(realurl); } KTextEditor::View *view = loadText(m_ki->extensions()->determineDocumentType(realurl), realurl, encoding, true, QString(), QString(), QString(), index); QList itemList = itemsFor(realurl); TextInfo *textInfo = textInfoFor(realurl); for(QList::iterator it = itemList.begin(); it != itemList.end(); ++it) { (*it)->setInfo(textInfo); } if(itemList.isEmpty()) { emit addToProjectView(realurl); loadDocumentAndViewSettings(textInfo); } else if(view) { KileProjectItem *item = itemList.first(); item->loadDocumentAndViewSettings(); } emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); // update undefined references in this file emit(updateReferences(textInfoFor(realurl))); m_currentlyOpeningFile = false; emit documentOpened(textInfo); return textInfo; } bool Manager::fileSave(KTextEditor::View *view) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!view && var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return false; } QUrl url = view->document()->url(); if(url.isEmpty()) { // newly created document return fileSaveAs(view); } else { bool ret = view->document()->documentSave(); emit(updateStructure(false, textInfoFor(view->document()))); return ret; } } bool Manager::fileSaveAs(KTextEditor::View* view) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!view && var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return false; } KTextEditor::Document* doc = view->document(); Q_ASSERT(doc); KileDocument::TextInfo* info = textInfoFor(doc); Q_ASSERT(info); QUrl startUrl = info->url(); QUrl oldURL = info->url(); if(startUrl.isEmpty()) { QUrl baseDirectory = info->getBaseDirectory(); if(baseDirectory.isEmpty()) { startUrl = QUrl("kfiledialog:///KILE_LATEX_SAVE_DIR"); } else { startUrl = baseDirectory; } } KILE_DEBUG_MAIN << "startUrl is " << startUrl; KEncodingFileDialog::Result result; QUrl saveURL; while(true) { QString filter = m_ki->extensions()->fileFilterKDEStyle(true, info->getFileFilter()); result = KEncodingFileDialog::getSaveUrlAndEncoding(doc->encoding(), startUrl, filter, m_ki->mainWindow(), i18n("Save File")); if(result.URLs.isEmpty() || result.URLs.first().isEmpty()) { return false; } saveURL = result.URLs.first(); if(info->getType() == KileDocument::LaTeX) { saveURL = Info::makeValidTeXURL(saveURL, m_ki->mainWindow(), m_ki->extensions()->isTexFile(saveURL), false); // don't check for file existence } auto statJob = KIO::stat(saveURL, KIO::StatJob::SourceSide, 0); KJobWidgets::setWindow(statJob, m_ki->mainWindow()); if (statJob->exec()) { // check for writing possibility int r = KMessageBox::warningContinueCancel(m_ki->mainWindow(), i18n("A file with the name \"%1\" exists already. Do you want to overwrite it?", saveURL.fileName()), i18n("Overwrite File?"), KStandardGuiItem::overwrite()); if(r != KMessageBox::Continue) { continue; } } break; } doc->setEncoding(result.encoding); if(!doc->saveAs(saveURL)) { return false; } if(oldURL != saveURL) { if(info->isDocumentTypePromotionAllowed()) { recreateTextDocumentInfo(info); info = textInfoFor(doc); } m_ki->structureWidget()->updateUrl(info); emit addToRecentFiles(saveURL); emit addToProjectView(doc->url()); } emit(documentSavedAs(view, info)); return true; } void Manager::fileSaveCopyAs() { KTextEditor::View *view = Q_NULLPTR; // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return; } KTextEditor::Document *doc = view->document(); if(!doc) { return; } KileDocument::TextInfo *originalInfo = textInfoFor(doc); if(!originalInfo) { return; } view = createDocumentWithText(doc->text(),originalInfo->getType()); KileDocument::TextInfo *newInfo = textInfoFor(view->document()); if(originalInfo->url().isEmpty()) { // untitled doc newInfo->setBaseDirectory(m_ki->fileSelector()->currentUrl()); } else { newInfo->setBaseDirectory(originalInfo->url()); } fileSaveAs(view); doc = view->document(); if(doc && !doc->isModified()) { // fileSaveAs was successful fileClose(doc); } } bool Manager::fileCloseAllOthers(KTextEditor::View *currentView) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!currentView && var.isValid()) { // the 'data' property for the relevant actions is cleared // inside the view manager currentView = var.value(); } } if(!currentView) { currentView = m_ki->viewManager()->currentTextView(); } if(!currentView) { return false; } QList viewList; for(int i = 0; i < m_ki->viewManager()->textViewCount(); ++i) { KTextEditor::View *view = m_ki->viewManager()->textView(i); if(currentView == view) { continue; } viewList.push_back(view); } for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { if (!fileClose(*it)) { return false; } } return true; } bool Manager::fileCloseAll() { KTextEditor::View * view = m_ki->viewManager()->currentTextView(); //assumes one view per doc here while(m_ki->viewManager()->textViewCount() > 0) { view = m_ki->viewManager()->textView(0); if (!fileClose(view->document())) { return false; } } return true; } bool Manager::fileClose(const QUrl &url) { KTextEditor::Document *doc = docFor(url); if(!doc) { return true; } else { return fileClose(doc); } } bool Manager::fileClose(KTextEditor::View *view) { // the 'data' property can be set by the view manager QAction *action = dynamic_cast(QObject::sender()); if(action) { QVariant var = action->data(); if(!view && var.isValid()) { view = var.value(); // the 'data' property for the relevant actions is cleared // inside the view manager } } if(!view) { view = m_ki->viewManager()->currentTextView(); } if(!view) { return false; } return fileClose(view->document()); } bool Manager::fileClose(KTextEditor::Document *doc /* = 0L*/, bool closingproject /*= false*/) { KILE_DEBUG_MAIN << "==Kile::fileClose=========================="; if(!doc) { doc = m_ki->activeTextDocument(); } if(!doc) { return true; } //FIXME: remove from docinfo map, remove from dirwatch KILE_DEBUG_MAIN << "doc->url().toLocalFile()=" << doc->url().toLocalFile(); const QUrl url = doc->url(); TextInfo *docinfo= textInfoFor(doc); if(!docinfo) { qWarning() << "no DOCINFO for " << url.url(); return true; } bool inProject = false; QList items = itemsFor(docinfo); for(QList::iterator it = items.begin(); it != items.end(); ++it) { KileProjectItem *item = *it; //FIXME: refactor here if(item && doc) { storeProjectItem(item, doc); inProject = true; } } if(!inProject) { KILE_DEBUG_MAIN << "not in project"; saveDocumentAndViewSettings(docinfo); } if(doc->closeUrl()) { // docinfo may have been recreated from 'Untitled' doc to a named doc if(url.isEmpty()) { docinfo= textInfoFor(doc); } if(KileConfig::cleanUpAfterClose()) { cleanUpTempFiles(url, true); // yes we pass here url and not docinfo->url() } //FIXME: use signal/slot if( doc->views().count() > 0){ m_ki->viewManager()->removeView(doc->views().first()); } //remove the decorations trashDoc(docinfo, doc); m_ki->structureWidget()->clean(docinfo); removeTextDocumentInfo(docinfo, closingproject); emit removeFromProjectView(url); emit updateModeStatus(); } else { return false; } return true; } void Manager::buildProjectTree(const QUrl &url) { KileProject * project = projectFor(url); if (project) { buildProjectTree(project); } } void Manager::buildProjectTree(KileProject *project) { if(!project) { project = activeProject(); } if(!project) { project = selectProject(i18n("Refresh Project Tree")); } if (project) { //TODO: update structure for all docs project->buildProjectTree(); } else if (m_projects.count() == 0) { KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to build the tree for, then choose Refresh Project Tree again."),i18n( "Could Not Refresh Project Tree")); } } void Manager::projectNew() { KileNewProjectDialog *dlg = new KileNewProjectDialog(m_ki->templateManager(), m_ki->extensions(), m_ki->mainWindow()); if (dlg->exec()) { TextInfo *newTextInfo = Q_NULLPTR; KileProject *project = dlg->project(); //add the project file to the project KileProjectItem *item = new KileProjectItem(project, project->url()); createTextInfoForProjectItem(item); item->setOpenState(false); projectOpenItem(item); if(dlg->createNewFile()) { m_currentlyOpeningFile = true; // don't let live preview interfere QString filename = dlg->file(); //create the new document and fill it with the template KTextEditor::View *view = loadTemplate(dlg->getSelection()); if(view) { //derive the URL from the base url of the project QUrl url = project->baseURL(); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + filename); newTextInfo = textInfoFor(view->document()); //save the new file //FIXME: this needs proper error handling view->document()->saveAs(url); emit(documentModificationStatusChanged(view->document(), false, KTextEditor::ModificationInterface::OnDiskUnmodified)); //add this file to the project item = new KileProjectItem(project, url); item->setInfo(newTextInfo); //docinfo->updateStruct(m_kwStructure->level()); emit(updateStructure(false, newTextInfo)); } m_currentlyOpeningFile = false; } project->buildProjectTree(); project->save(); addProject(project); emit(updateModeStatus()); emit(addToRecentProjects(project->url())); if(newTextInfo) { emit documentOpened(newTextInfo); } } } void Manager::addProject(KileProject *project) { KILE_DEBUG_MAIN << "==void Manager::addProject(const KileProject *project)=========="; m_projects.append(project); KILE_DEBUG_MAIN << "\tnow " << m_projects.count() << " projects"; emit addToProjectView(project); connect(project, SIGNAL(projectTreeChanged(const KileProject *)), this, SIGNAL(projectTreeChanged(const KileProject *))); } KileProject* Manager::selectProject(const QString& caption) { QStringList list; for(QList::iterator it = m_projects.begin(); it != m_projects.end(); ++it) { list.append((*it)->name()); } KileProject *project = Q_NULLPTR; QString name; if (list.count() > 1) { KileListSelector *dlg = new KileListSelector(list, caption, i18n("Select Project"), true, m_ki->mainWindow()); if (dlg->exec()) { if(!dlg->hasSelection()) { return Q_NULLPTR; } name = dlg->selectedItems().first(); } delete dlg; } else if (list.count() == 0) { return Q_NULLPTR; } else { name = m_projects.first()->name(); } project = projectFor(name); return project; } void Manager::addToProject(const QUrl &url) { KILE_DEBUG_MAIN << "===Kile::addToProject(const QUrl &url =" << url.url() << ")"; KileProject *project = selectProject(i18n("Add to Project")); if (project) { addToProject(project, url); } } void Manager::addToProject(KileProject* project, const QUrl &url) { const QUrl realurl = symlinkFreeURL(url); QFileInfo fi(realurl.toLocalFile()); if (project->contains(realurl)) { m_ki->errorHandler()->printMessage(KileTool::Info, i18n("The file %1 is already member of the project %2", realurl.fileName(), project->name()), i18n("Add to Project")); return; } else if(!fi.exists() || !fi.isReadable()) { m_ki->errorHandler()->printMessage(KileTool::Info, i18n("The file %1 can not be added because it does not exist or is not readable", realurl.fileName()), i18n("Add to Project")); return; } KileProjectItem *item = new KileProjectItem(project, realurl); createTextInfoForProjectItem(item); item->setOpenState(m_ki->isOpen(realurl)); projectOpenItem(item); emit addToProjectView(item); buildProjectTree(project); } void Manager::removeFromProject(KileProjectItem *item) { if (item && item->project()) { KILE_DEBUG_MAIN << "\tprojecturl = " << item->project()->url().toLocalFile() << ", url = " << item->url().toLocalFile(); if (item->project()->url() == item->url()) { KMessageBox::error(m_ki->mainWindow(), i18n("This file is the project file, which holds all the information about your project. As such, it cannot be removed from the project."), i18n("Cannot Remove File From Project")); return; } emit removeItemFromProjectView(item, m_ki->isOpen(item->url())); KileProject *project = item->project(); project->remove(item); // update undefined references in all project files updateProjectReferences(project); project->buildProjectTree(); } } // WARNING: 'item' must have been set up with a TextInfo* object already void Manager::projectOpenItem(KileProjectItem *item, bool openProjectItemViews) { KILE_DEBUG_MAIN << "==Kile::projectOpenItem=========================="; KILE_DEBUG_MAIN << "\titem:" << item->url().toLocalFile(); if (m_ki->isOpen(item->url())) { //remove item from projectview (this file was opened before as a normal file) emit removeFromProjectView(item->url()); } KileDocument::TextInfo* itemInfo = item->getInfo(); Q_ASSERT(itemInfo); if(item->isOpen()) { KTextEditor::View *view = loadItem(m_ki->extensions()->determineDocumentType(item->url()), item, QString(), openProjectItemViews); if (view) { item->loadDocumentAndViewSettings(); } // make sure that the item has been parsed, even if it isn't shown; // this is necessary to identify the correct LaTeX root document (bug 233667); m_ki->structureWidget()->update(itemInfo, true); } else if(item->type() == KileProjectItem::Source || item->type() == KileProjectItem::Package || item->type() == KileProjectItem::Bibliography) { // 'item' is not shown (and it is either a LaTeX source file or package), i.e. its // contents won't be loaded into a KTextEditor::Document; so, we have to do it: // we are loading the contents of the project item into the docinfo // for a moment itemInfo->setDocumentContents(loadTextURLContents(item->url(), item->encoding())); // in order to pass the contents to the parser m_ki->structureWidget()->update(itemInfo, true); // now we don't need the contents anymore itemInfo->setDocumentContents(QStringList()); } } void Manager::createTextInfoForProjectItem(KileProjectItem *item) { item->setInfo(createTextDocumentInfo(m_ki->extensions()->determineDocumentType(item->url()), item->url(), item->project()->baseURL())); } void Manager::projectOpen(const QUrl &url, int step, int max, bool openProjectItemViews) { KILE_DEBUG_MAIN << "==Kile::projectOpen=========================="; KILE_DEBUG_MAIN << "\tfilename: " << url.fileName(); const QUrl realurl = symlinkFreeURL(url); if(m_ki->projectIsOpen(realurl)) { if(m_progressDialog) { m_progressDialog->hide(); } KMessageBox::information(m_ki->mainWindow(), i18n("

The project \"%1\" is already open.

" "

If you wanted to reload the project, close the project before you re-open it.

", url.fileName()), i18n("Project Already Open")); return; } QFileInfo fi(realurl.toLocalFile()); if(!fi.isReadable()) { if(m_progressDialog) { m_progressDialog->hide(); } if (KMessageBox::warningYesNo(m_ki->mainWindow(), i18n("

The project file for the project \"%1\" does not exist or it is not readable.

" "

Do you want to remove this project from the recent projects list?

", url.fileName()), i18n("Could Not Open Project")) == KMessageBox::Yes) { emit(removeFromRecentProjects(realurl)); } return; } if(!m_progressDialog) { createProgressDialog(); } KileProject *kp = new KileProject(realurl, m_ki->extensions()); if(!kp->appearsToBeValidProjectFile()) { if(m_progressDialog) { m_progressDialog->hide(); } KMessageBox::sorry(m_ki->mainWindow(), i18n("

The file \"%1\" cannot be opened as it does not appear to be a project file.

", url.fileName()), i18n("Impossible to Open Project File")); delete kp; return; } if(kp->getProjectFileVersion() > KILE_PROJECTFILE_VERSION) { if(m_progressDialog) { m_progressDialog->hide(); } KMessageBox::sorry(m_ki->mainWindow(), i18n("

The project \"%1\" cannot be opened as it was created
by a newer version of Kile.

", url.fileName()), i18n("Impossible to Open Project")); delete kp; return; } if(!kp->isOfCurrentVersion()) { if(m_progressDialog) { m_progressDialog->hide(); } if(KMessageBox::questionYesNo(m_ki->mainWindow(), i18n("

The project file \"%1\" was created by a previous version of Kile.
" "It needs to be updated before it can be opened.

" "

Do you want to update it?

", url.fileName()), i18n("Project File Needs to be Updated")) == KMessageBox::No) { delete kp; return; } if(!kp->migrateProjectFileToCurrentVersion()) { if (KMessageBox::warningYesNo(m_ki->mainWindow(), i18n("

The project file \"%1\" could be not updated.

" "

Do you want to remove this project from the recent projects list?

", url.fileName()), i18n("Could Not Update Project File")) == KMessageBox::Yes) { emit(removeFromRecentProjects(realurl)); } delete kp; return; } } m_progressDialog->show(); kp->load(); if(kp->isInvalid()) { if(m_progressDialog) { m_progressDialog->hide(); } delete kp; return; } emit(addToRecentProjects(realurl)); QList list = kp->items(); int project_steps = list.count(); m_progressDialog->setMaximum(project_steps * max); project_steps *= step; m_progressDialog->setValue(project_steps); // open the project files in the correct order QVector givenPositionVector(list.count(), Q_NULLPTR); QList notCorrectlyOrderedList; for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; int order = item->order(); if(order >= 0 && order >= list.count()) { order = -1; } if(!item->isOpen() || order < 0 || givenPositionVector[order] != Q_NULLPTR) { notCorrectlyOrderedList.push_back(item); } else { givenPositionVector[order] = item; } } QList orderedList; for(int i = 0; i < givenPositionVector.size(); ++i) { KileProjectItem *item = givenPositionVector[i]; if(item) { orderedList.push_back(item); } } for(QList::iterator i = notCorrectlyOrderedList.begin(); i != notCorrectlyOrderedList.end(); ++i) { orderedList.push_back(*i); } addProject(kp); // for the parsing to work correctly, all ProjectItems need to have TextInfo* objects, but // the URL of 'item' might already be associated with a TextInfo* object; for example, through // a stand-alone document currently being open already, or through a project item that belongs to // a different project // => 'createTextDocumentInfo' will take care of that situation as well for (QList::iterator i = orderedList.begin(); i != orderedList.end(); ++i) { createTextInfoForProjectItem(*i); } unsigned int counter = 1; for (QList::iterator i = orderedList.begin(); i != orderedList.end(); ++i) { projectOpenItem(*i, openProjectItemViews); m_progressDialog->setValue(counter + project_steps); qApp->processEvents(); ++counter; } kp->buildProjectTree(); emit(updateStructure(false, Q_NULLPTR)); emit(updateModeStatus()); // update undefined references in all project files updateProjectReferences(kp); m_ki->viewManager()->switchToTextView(kp->lastDocument()); emit(projectOpened(kp)); } // as all labels are gathered in the project, we can check for unsolved references void Manager::updateProjectReferences(KileProject *project) { QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { emit(updateReferences((*it)->getInfo())); } } void Manager::projectOpen() { KILE_DEBUG_MAIN << "==Kile::projectOpen=========================="; QUrl url = QFileDialog::getOpenFileUrl(m_ki->mainWindow(), i18n("Open Project"), QUrl::fromLocalFile(KileConfig::defaultProjectLocation()), m_ki->extensions()->fileFilterQtStyle(false, {KileDocument::Extensions::KILE_PROJECT})); if(!url.isEmpty()) { projectOpen(url); } } void Manager::projectSave(KileProject *project /* = 0 */) { KILE_DEBUG_MAIN << "==Kile::projectSave=========================="; if (!project) { //find the project that corresponds to the active doc project= activeProject(); } if(!project) { project = selectProject(i18n("Save Project")); } if(project) { QList list = project->items(); KTextEditor::Document *doc = Q_NULLPTR; KileProjectItem *item = Q_NULLPTR; TextInfo *docinfo = Q_NULLPTR; // determine the order in which the project items are opened QVector viewPositionVector(m_ki->viewManager()->getTabCount(), Q_NULLPTR); for(QList::iterator i = list.begin(); i != list.end(); ++i) { docinfo = (*i)->getInfo(); if(docinfo) { KTextEditor::View *view = m_ki->viewManager()->textView(docinfo); if(view) { int position = m_ki->viewManager()->tabIndexOf(view); if(position >= 0 && position < viewPositionVector.size()) { viewPositionVector[position] = *i; } } } } int position = 0; for(int i = 0; i < viewPositionVector.size(); ++i) { if(viewPositionVector[i] != Q_NULLPTR) { viewPositionVector[i]->setOrder(position); ++position; } } //update the open-state of the items for (QList::iterator i = list.begin(); i != list.end(); ++i) { item = *i; KILE_DEBUG_MAIN << "\tsetOpenState(" << (*i)->url().toLocalFile() << ") to " << m_ki->isOpen(item->url()); item->setOpenState(m_ki->isOpen(item->url())); docinfo = item->getInfo(); if(docinfo) { doc = docinfo->getDoc(); } if(doc) { storeProjectItem(item, doc); } doc = Q_NULLPTR; docinfo = Q_NULLPTR; } project->save(); } else { KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to save, then choose Save Project again."),i18n( "Could Determine Active Project")); } } void Manager::projectAddFiles(const QUrl &url) { KileProject *project = projectFor(url); if (project) { projectAddFiles(project,url); } } void Manager::projectAddFiles(KileProject *project,const QUrl &fileUrl) { KILE_DEBUG_MAIN << "==Kile::projectAddFiles()=========================="; if(project == 0) { project = activeProject(); } if(project == 0) { project = selectProject(i18n("Add Files to Project")); } if (project) { QString currentDir; if(fileUrl.isEmpty()) { currentDir = QFileInfo(project->url().path()).dir().dirName(); } else { currentDir = fileUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path(); } KILE_DEBUG_MAIN << "currentDir is " << currentDir; QFileDialog *dlg = new QFileDialog(m_ki->mainWindow(), i18n("Add Files"), currentDir, m_ki->extensions()->fileFilterQtStyle(true, {})); dlg->setModal(true); dlg->setFileMode(QFileDialog::ExistingFiles); dlg->setLabelText(QFileDialog::Accept, i18n("Add")); if(dlg->exec()) { QList urls = dlg->selectedUrls(); for(int i=0; i < urls.count(); ++i) { addToProject(project, urls[i]); } // update undefined references in all project files updateProjectReferences(project); } delete dlg; //open them } else if (m_projects.count() == 0) { KMessageBox::error(m_ki->mainWindow(), i18n("There are no projects opened. Please open the project you want to add files to, then choose Add Files again."),i18n( "Could Not Determine Active Project")); } } void Manager::toggleArchive(KileProjectItem *item) { item->setArchive(!item->archive()); } void Manager::projectOptions(const QUrl &url) { KileProject *project = projectFor(url); if (project) { projectOptions(project); } } void Manager::projectOptions(KileProject *project /* = 0*/) { KILE_DEBUG_MAIN << "==Kile::projectOptions=========================="; if(!project) { project = activeProject(); } if(!project) { project = selectProject(i18n("Project Options For")); } if (project) { KILE_DEBUG_MAIN << "\t" << project->name(); KileProjectOptionsDialog *dlg = new KileProjectOptionsDialog(project, m_ki->extensions(), m_ki->mainWindow()); dlg->exec(); } else if (m_projects.count() == 0) { KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to modify, then choose Project Options again."),i18n( "Could Not Determine Active Project")); } } bool Manager::projectCloseAll() { KILE_DEBUG_MAIN << "==Kile::projectCloseAll=========================="; while(m_projects.size() > 0) { if(!projectClose(m_projects.first()->url())) { return false; } } return true; } bool Manager::projectClose(const QUrl &url) { KILE_DEBUG_MAIN << "==Kile::projectClose=========================="; KileProject *project = 0; if (url.isEmpty()) { project = activeProject(); if (!project) { project = selectProject(i18n("Close Project")); } } else { project = projectFor(url); } if(project) { KILE_DEBUG_MAIN << "\tclosing:" << project->name(); project->setLastDocument(QUrl::fromLocalFile(m_ki->getName())); projectSave(project); QList list = project->items(); bool close = true; KTextEditor::Document *doc = Q_NULLPTR; TextInfo *docinfo = Q_NULLPTR; for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; doc = Q_NULLPTR; docinfo = item->getInfo(); if (docinfo) { doc = docinfo->getDoc(); } else { continue; } if (doc) { KILE_DEBUG_MAIN << "\t\tclosing item " << doc->url().toLocalFile(); bool r = fileClose(doc, true); close = close && r; if (!close) { break; } } else { // we still need to delete the TextInfo object removeTextDocumentInfo(docinfo, true); } } if (close) { m_projects.removeAll(project); emit removeFromProjectView(project); delete project; emit(updateModeStatus()); return true; } else return false; } else if (m_projects.count() == 0) KMessageBox::error(m_ki->mainWindow(), i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to close, then choose Close Project again."),i18n( "Could Not Close Project")); return true; } void Manager::storeProjectItem(KileProjectItem *item, KTextEditor::Document *doc) { KILE_DEBUG_MAIN << "===Kile::storeProjectItem=============="; KILE_DEBUG_MAIN << "\titem = " << item << ", doc = " << doc; item->setEncoding(doc->encoding()); item->setMode(doc->mode()); item->setHighlight(doc->highlightingMode()); item->saveDocumentAndViewSettings(); } void Manager::cleanUpTempFiles(const QUrl &url, bool silent) { KILE_DEBUG_MAIN << "===void Manager::cleanUpTempFiles(const QUrl " << url.toLocalFile() << ", bool " << silent << ")==="; if( url.isEmpty() ) return; QStringList extlist; QFileInfo fi(url.toLocalFile()); const QStringList templist = KileConfig::cleanUpFileExtensions().split(' '); const QString fileName = fi.fileName(); const QString dirPath = fi.absolutePath(); const QString baseName = fi.completeBaseName(); for (int i = 0; i < templist.count(); ++i) { fi.setFile( dirPath + '/' + baseName + templist[i] ); if(fi.exists()) { extlist.append(templist[i]); } } if(!silent && fileName.isEmpty()) { return; } if (!silent && extlist.count() > 0) { KILE_DEBUG_MAIN << "not silent"; KileDialog::Clean *dialog = new KileDialog::Clean(m_ki->mainWindow(), fileName, extlist); if (dialog->exec() == QDialog::Accepted) { extlist = dialog->cleanList(); } else { delete dialog; return; } delete dialog; } if(extlist.count() == 0) { m_ki->errorHandler()->printMessage(KileTool::Warning, i18n("Nothing to clean for %1", fileName), i18n("Clean")); } else { for(int i = 0; i < extlist.count(); ++i) { QFile file(dirPath + '/' + baseName + extlist[i]); KILE_DEBUG_MAIN << "About to remove file = " << file.fileName(); file.remove(); } m_ki->errorHandler()->printMessage(KileTool::Info, i18n("Cleaning %1: %2", fileName, extlist.join(" ")), i18n("Clean")); } } void Manager::openDroppedURLs(QDropEvent *e) { QList urls = e->mimeData()->urls(); Extensions *extensions = m_ki->extensions(); for(QList::iterator i = urls.begin(); i != urls.end(); ++i) { QUrl url = *i; if(extensions->isProjectFile(url)) { projectOpen(url); } else { fileOpen(url); } } } void Manager::reloadXMLOnAllDocumentsAndViews() { for(QList::iterator it = m_textInfoList.begin(); it != m_textInfoList.end(); ++it) { KTextEditor::Document *doc = (*it)->getDoc(); // FIXME: 'doc' can be null, for example if it belongs to a project item // which has been closed, but this should be improved in the sense // that 'm_textInfoList' should only contain 'TextInfo' objects which // contain valid pointers to 'KTextEditor::Document' objects. if(!doc) { continue; } doc->reloadXML(); QList views = doc->views(); for(QList::iterator viewIt = views.begin(); viewIt != views.end(); ++viewIt) { (*viewIt)->reloadXML(); } } } void Manager::handleParsingComplete(const QUrl &url, KileParser::ParserOutput* output) { KILE_DEBUG_MAIN << url << output; if(!output) { KILE_DEBUG_MAIN << "NULL output given"; return; } KileDocument::TextInfo *textInfo = textInfoFor(url); if(!textInfo) { KileProjectItem* item = itemFor(url); if(item) { textInfo = item->getInfo(); } if(!textInfo) { // this can happen for instance when the document is closed // while the parser is still running KILE_DEBUG_MAIN << "no TextInfo object found for" << url << "found"; return; } } textInfo->installParserOutput(output); m_ki->structureWidget()->updateAfterParsing(textInfo, output->structureViewItems); delete(output); } // Show all opened projects and switch to another one, if you want void Manager::projectShow() { if(m_projects.count() <= 1) { return; } // select the new project KileProject *project = selectProject(i18n("Switch Project")); if(!project || project==activeProject()) { return; } // get last opened document const QUrl lastdoc = project->lastDocument(); KileProjectItem *docitem = (!lastdoc.isEmpty()) ? itemFor(lastdoc, project) : Q_NULLPTR; // if not, we search for the first opened tex file of this project // if no file is opened, we take the first tex file mentioned in the list KileProjectItem *first_texitem = Q_NULLPTR; if(!docitem) { QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; QString itempath = item->path(); // called from QAction 'Show projects...': find the first opened // LaTeX document or, if that fails, any other opened file QStringList extlist = (m_ki->extensions()->latexDocuments() + ' ' + m_ki->extensions()->latexPackages()).split(' '); for(QStringList::Iterator it=extlist.begin(); it!=extlist.end(); ++it) { if(itempath.indexOf( (*it), -(*it).length() ) >= 0) { if (m_ki->isOpen(item->url())) { docitem = item; break; } else if(!first_texitem) { first_texitem = item; } } } if(docitem) { break; } } } // did we find one opened file or must we take the first entry if(!docitem) { if(!first_texitem) { return; } docitem = first_texitem; } // ok, we can switch to another project now if (m_ki->isOpen(docitem->url())) { m_ki->viewManager()->switchToTextView(docitem->url()); } else { fileOpen(docitem->url(), docitem->encoding()); } } void Manager::projectRemoveFiles() { QList itemsList = selectProjectFileItems(i18n("Select Files to Remove")); if(itemsList.count() > 0) { for(QList::iterator it = itemsList.begin(); it != itemsList.end(); ++it) { removeFromProject(*it); } } } void Manager::projectShowFiles() { KileProjectItem *item = selectProjectFileItem( i18n("Select File") ); if(item) { if (item->type() == KileProjectItem::ProjectFile) { dontOpenWarning(item, i18n("Show Project Files"), i18n("project configuration file")); } else if(item->type() == KileProjectItem::Image) { dontOpenWarning(item, i18n("Show Project Files"), i18n("graphics file")); } else { // ok, we can switch to another file if (m_ki->isOpen(item->url())) { m_ki->viewManager()->switchToTextView(item->url()); } else { fileOpen(item->url(), item->encoding() ); } } } } void Manager::projectOpenAllFiles() { KileProject *project = selectProject(i18n("Select Project")); if(project) { projectOpenAllFiles(project->url()); } } void Manager::projectOpenAllFiles(const QUrl &url) { KileProject* project; KTextEditor::Document* doc = Q_NULLPTR; if(!url.isValid()) { return; } project = projectFor(url); if(!project) return; if(m_ki->viewManager()->currentTextView()) { doc = m_ki->viewManager()->currentTextView()->document(); } // we remember the actual view, so the user gets the same view back after opening QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; if (item->type()==KileProjectItem::ProjectFile) { dontOpenWarning( item, i18n("Open All Project Files"), i18n("project configuration file") ); } else if(item->type()==KileProjectItem::Image) { dontOpenWarning( item, i18n("Open All Project Files"), i18n("graphics file") ); } else if(!m_ki->isOpen(item->url())) { fileOpen(item->url(), item->encoding()); } } if(doc) { // we have a doc so switch back to original view m_ki->viewManager()->switchToTextView(doc->url()); } } QStringList Manager::getProjectFiles() { QStringList filelist; KileProject *project = activeProject(); if ( project ) { QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; if(item->type() != KileProjectItem::ProjectFile && item->type() != KileProjectItem::Image) { filelist << item->url().toLocalFile(); } } } return filelist; } void Manager::dontOpenWarning(KileProjectItem *item, const QString &action, const QString &filetype) { m_ki->errorHandler()->printMessage(KileTool::Info, i18n("not opened: %1 (%2)", item->url().toLocalFile(), filetype), action); } KileProjectItem* Manager::selectProjectFileItem(const QString &label) { // select a project KileProject *project = selectProject(i18n("Select Project")); if(!project) { return Q_NULLPTR; } // get a list of files QStringList filelist; QMap map; QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; filelist << item->path(); map[item->path()] = item; } // select one of these files KileProjectItem *item = Q_NULLPTR; KileListSelector *dlg = new KileListSelector(filelist, i18n("Project Files"), label, true, m_ki->mainWindow()); if(dlg->exec()) { if(dlg->hasSelection()) { QString name = dlg->selectedItems().first(); if(map.contains(name)) { item = map[name]; } else { KMessageBox::error(m_ki->mainWindow(), i18n("Could not determine the selected file."),i18n( "Project Error")); } } } delete dlg; return item; } QList Manager::selectProjectFileItems(const QString &label) { KileProject *project = selectProject(i18n("Select Project")); if(!project) { return QList(); } QStringList filelist; QMap map; QList list = project->items(); for(QList::iterator it = list.begin(); it != list.end(); ++it) { KileProjectItem *item = *it; filelist << item->path(); map[item->path()] = item; } QList itemsList; KileListSelector *dlg = new KileListSelector(filelist, i18n("Project Files"), label, true, m_ki->mainWindow()); dlg->setSelectionMode(QAbstractItemView::ExtendedSelection); if(dlg->exec()) { if(dlg->hasSelection()) { QStringList selectedfiles = dlg->selectedItems(); for(QStringList::Iterator it = selectedfiles.begin(); it != selectedfiles.end(); ++it ){ if(map.contains(*it)) { itemsList.append(map[(*it)]); } else { KMessageBox::error(m_ki->mainWindow(), i18n("Could not determine the selected file."), i18n( "Project Error")); } } } } delete dlg; return itemsList; } // add a new file to the project // - only when there is an active project // - if the file doesn't already belong to it (checked by addToProject) void Manager::projectAddFile(QString filename, bool graphics) { KILE_DEBUG_MAIN << "===Kile::projectAddFile=============="; KileProject *project = activeProject(); if(!project) { return; } QFileInfo fi(filename); if(!fi.exists()) { if(graphics) { return; } // called from InputDialog after a \input- or \include command: // - if the chosen file has an extension: accept // - if not we add the default TeX extension: accept if it exists else reject QString ext = fi.completeSuffix(); if ( ! ext.isEmpty() ) { return; } filename += m_ki->extensions()->latexDocumentDefault(); if ( QFileInfo(filename).exists() ) { return; } } //ok, we have a project and an existing file KILE_DEBUG_MAIN << "\tadd file: " << filename; m_ki->viewManager()->updateStructure(false); QUrl url; url.setPath(filename); addToProject(project, url); } const QUrl Manager::symlinkFreeURL(const QUrl &url) { #ifdef Q_OS_WIN //TODO: maybe actually do something here? Seems unncecessary given Windows' lack of symlinks though... //Also: the else'd code below fails badly on Windows return url; #else KILE_DEBUG_MAIN << "===symlinkFreeURL=="; if(!url.isLocalFile()) { return url; } QDir dir(url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).path()); QString filename = url.toLocalFile(); // if the directory does not exist we return the old url (just to be sure) if(dir.exists()) { filename= dir.canonicalPath() + '/' + url.fileName(); } else { KILE_DEBUG_MAIN << "directory " << url.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash).path() << "does not exist"; } QFileInfo fi(filename); if (fi.isSymLink()) { filename = fi.symLinkTarget(); } return QUrl::fromLocalFile(filename); #endif //def Q_OS_WIN } void Manager::cleanupDocumentInfoForProjectItems(KileDocument::Info *info) { QList itemsList = itemsFor(info); for(QList::iterator it = itemsList.begin(); it != itemsList.end(); ++it) { (*it)->setInfo(Q_NULLPTR); } } void Manager::createProgressDialog() { //TODO this is a dangerous dialog and should be removed in the long-term: // the dialog disables all close events unless all files are loaded, // thus if there is a loading error, the only way to abort loading gracefully is to // terminate the application m_progressDialog = new KileWidget::ProgressDialog(m_ki->mainWindow()); QLabel *label = new QLabel(m_progressDialog); label->setText(i18n("Opening Project...")); m_progressDialog->setLabel(label); m_progressDialog->setModal(true); m_progressDialog->setLabelText(i18n("Scanning project files...")); m_progressDialog->setAutoClose(true); m_progressDialog->setMinimumDuration(2000); m_progressDialog->hide(); } void Manager::loadDocumentAndViewSettings(KileDocument::TextInfo *textInfo) { KTextEditor::Document *document = textInfo->getDoc(); if(!document) { return; } KConfigGroup configGroup = configGroupForDocumentSettings(document); if(!configGroup.exists()) { return; } document->readSessionConfig(configGroup, QSet() << "SkipEncoding" << "SkipUrl"); { LaTeXInfo *latexInfo = dynamic_cast(textInfo); if(latexInfo) { KileTool::LivePreviewManager::readLivePreviewStatusSettings(configGroup, latexInfo); } } { LaTeXOutputHandler *h = dynamic_cast(textInfo); if(h) { h->readBibliographyBackendSettings(configGroup); } } QList viewList = document->views(); int i = 0; for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { KTextEditor::View *view = *it; configGroup = configGroupForViewSettings(document, i); view->readSessionConfig(configGroup); ++i; } } void Manager::saveDocumentAndViewSettings(KileDocument::TextInfo *textInfo) { KTextEditor::Document *document = textInfo->getDoc(); if(!document) { return; } KConfigGroup configGroup = configGroupForDocumentSettings(document); QUrl url = document->url(); url.setPassword(""); // we don't want the password to appear in the configuration file deleteDocumentAndViewSettingsGroups(url); document->writeSessionConfig(configGroup, QSet() << "SkipEncoding" << "SkipUrl"); { LaTeXInfo *latexInfo = dynamic_cast(textInfo); if(latexInfo) { KileTool::LivePreviewManager::writeLivePreviewStatusSettings(configGroup, latexInfo); } } { LaTeXOutputHandler *h = dynamic_cast(textInfo); if(h) { h->writeBibliographyBackendSettings(configGroup); } } QList viewList = document->views(); int i = 0; for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { configGroup = configGroupForViewSettings(document, i); (*it)->writeSessionConfig(configGroup); ++i; } // finally remove the config groups for the oldest documents that exceed MAX_NUMBER_OF_STORED_SETTINGS configGroup = KSharedConfig::openConfig()->group("Session Settings"); QList urlList = QUrl::fromStringList(configGroup.readEntry("Saved Documents", QStringList())); urlList.removeAll(url); urlList.push_front(url); // remove excess elements if(urlList.length() > MAX_NUMBER_OF_STORED_SETTINGS) { int excessNumber = urlList.length() - MAX_NUMBER_OF_STORED_SETTINGS; for(; excessNumber > 0; --excessNumber) { QUrl url = urlList.takeLast(); deleteDocumentAndViewSettingsGroups(url); } } configGroup.writeEntry("Documents", url); configGroup.writeEntry("Saved Documents", QUrl::toStringList(urlList)); } KConfigGroup Manager::configGroupForDocumentSettings(KTextEditor::Document *doc) const { return KSharedConfig::openConfig()->group(configGroupNameForDocumentSettings(doc->url())); } QString Manager::configGroupNameForDocumentSettings(const QUrl &url) const { QUrl url2 = url; url2.setPassword(""); return "Document-Settings,URL=" + url2.url(); } KConfigGroup Manager::configGroupForViewSettings(KTextEditor::Document *doc, int viewIndex) const { return KSharedConfig::openConfig()->group(configGroupNameForViewSettings(doc->url(), viewIndex)); } QString Manager::configGroupNameForViewSettings(const QUrl &url, int viewIndex) const { QUrl url2 = url; url2.setPassword(""); return "View-Settings,View=" + QString::number(viewIndex) + ",URL=" + url2.url(); } void Manager::deleteDocumentAndViewSettingsGroups(const QUrl &url) { QString urlString = url.url(); - QStringList groupList = KSharedConfig::openConfig()->groupList(); - for(QStringList::iterator i = groupList.begin(); i != groupList.end(); ++i) { - QString groupName = *i; + const QStringList groupList = KSharedConfig::openConfig()->groupList(); + for(auto groupName : groupList) { + if(!KSharedConfig::openConfig()->hasGroup(groupName)) { // 'groupName' might have been deleted + continue; // work around bug 384039 + } if(groupName.startsWith("Document-Settings") || groupName.startsWith("View-Settings")) { int urlIndex = groupName.indexOf("URL="); if(urlIndex >= 0 && groupName.mid(urlIndex + 4) == urlString) { KSharedConfig::openConfig()->deleteGroup(groupName); } } } } QStringList Manager::loadTextURLContents(const QUrl &url, const QString& encoding) { QTemporaryFile *temporaryFile = Q_NULLPTR; QString localFileName; if(url.isLocalFile()) { localFileName = url.path(); } else { // only use KIO when we have to temporaryFile = new QTemporaryFile(); if(!temporaryFile->open()) { KILE_DEBUG_MAIN << "Cannot create temporary file for" << url; delete temporaryFile; return QStringList(); } localFileName = temporaryFile->fileName(); auto downloadJob = KIO::file_copy(url, QUrl::fromLocalFile(localFileName), 0600, KIO::Overwrite); KJobWidgets::setWindow(downloadJob, m_ki->mainWindow()); // FIXME: 'exec' should not be used! if (!downloadJob->exec()) { KILE_DEBUG_MAIN << "Cannot download resource: " << url; KILE_DEBUG_MAIN << downloadJob->errorString(); delete temporaryFile; return QStringList(); } } QFile localFile(localFileName); if (!localFile.open(QIODevice::ReadOnly | QIODevice::Text)) { KILE_DEBUG_MAIN << "Cannot open source file: " << localFileName; delete temporaryFile; return QStringList(); } QStringList res; QTextStream stream(&localFile); if(!encoding.isEmpty()) { stream.setCodec(encoding.toLatin1()); } while(!stream.atEnd()) { res.append(stream.readLine()); } delete temporaryFile; return res; } } diff --git a/src/kileproject.cpp b/src/kileproject.cpp index 142ae3f8..39978152 100644 --- a/src/kileproject.cpp +++ b/src/kileproject.cpp @@ -1,1002 +1,1009 @@ /******************************************************************************************** begin : Fri Aug 1 2003 copyright : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) (C) 2007 by Holger Danielsson (holger.danielsson@versanet.de) (C) 2009-2016 by Michel Ludwig (michel.ludwig@kdemail.net) *********************************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ // 2007-03-12 dani // - use KileDocument::Extensions // - allowed extensions are always defined as list, f.e.: .tex .ltx .latex #include "kileproject.h" #include #include #include #include #include #include #include #include "documentinfo.h" #include "kiledebug.h" #include "kiledocmanager.h" #include "kiletoolmanager.h" #include "kileinfo.h" #include "kileextensions.h" #include "livepreview.h" /** * Since project file version 3, project files 'consist' of two files: one file named '.kilepr' and * one file named '.kilepr.gui' located in the '.kile' subdirectory of the project directory. * The former files contains the static structure of the project, and the later contains the current gui display settings * (like which file is open or on which line and column the cursors are). */ /* * KileProjectItem */ KileProjectItem::KileProjectItem(KileProject *project, const QUrl &url, int type) : m_project(project), m_url(url), m_type(type), m_docinfo(Q_NULLPTR), m_parent(Q_NULLPTR), m_child(Q_NULLPTR), m_sibling(Q_NULLPTR), m_order(-1) { m_bOpen = m_archive = true; if (project) { project->add(this); } } void KileProjectItem::setOrder(int i) { m_order = i; } void KileProjectItem::setParent(KileProjectItem * item) { m_parent = item; //update parent info if (m_parent) { if (m_parent->firstChild()) { //get last child KileProjectItem *sib = m_parent->firstChild(); while (sib->sibling()) { sib = sib->sibling(); } sib->setSibling(this); } else { m_parent->setChild(this); } } else { setChild(0); setSibling(0); } } void KileProjectItem::load() { KConfigGroup projectConfigGroup = m_project->configGroupForItem(this, KileProject::ProjectFile); KConfigGroup guiConfigGroup = m_project->configGroupForItem(this, KileProject::GUIFile); // project: archive, highlight, mode // gui: column, encoding, line, open, order setEncoding(projectConfigGroup.readEntry("encoding", QString())); setMode(projectConfigGroup.readEntry("mode", QString())); setHighlight(projectConfigGroup.readEntry("highlight", QString())); setArchive(projectConfigGroup.readEntry("archive", true)); setOpenState(guiConfigGroup.readEntry("open", true)); setOrder(guiConfigGroup.readEntry("order", -1)); } void KileProjectItem::save() { KConfigGroup projectConfigGroup = m_project->configGroupForItem(this, KileProject::ProjectFile); KConfigGroup guiConfigGroup = m_project->configGroupForItem(this, KileProject::GUIFile); // project: archive, highlight, mode // gui: encoding, open, order projectConfigGroup.writeEntry("encoding", encoding()); projectConfigGroup.writeEntry("mode", mode()); projectConfigGroup.writeEntry("highlight", highlight()); projectConfigGroup.writeEntry("archive", archive()); guiConfigGroup.writeEntry("open", isOpen()); guiConfigGroup.writeEntry("order", order()); } void KileProjectItem::loadDocumentAndViewSettings() { if(!m_docinfo) { return; } KTextEditor::Document *document = m_docinfo->getDocument(); if(!document) { return; } QList viewList = document->views(); loadDocumentSettings(document); int i = 0; for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { loadViewSettings(*it, i); ++i; } } void KileProjectItem::saveDocumentAndViewSettings() { if(!m_docinfo) { return; } KTextEditor::Document *document = m_docinfo->getDocument(); if(!document) { return; } QList viewList = document->views(); saveDocumentSettings(document); int i = 0; for(QList::iterator it = viewList.begin(); it != viewList.end(); ++it) { saveViewSettings(*it, i); ++i; } } void KileProjectItem::loadViewSettings(KTextEditor::View *view, int viewIndex) { KConfigGroup configGroup = m_project->configGroupForItemViewSettings(this, viewIndex); view->readSessionConfig(configGroup); } void KileProjectItem::saveViewSettings(KTextEditor::View *view, int viewIndex) { KConfigGroup configGroup = m_project->configGroupForItemViewSettings(this, viewIndex); view->writeSessionConfig(configGroup); } void KileProjectItem::loadDocumentSettings(KTextEditor::Document *document) { KConfigGroup configGroup = m_project->configGroupForItemDocumentSettings(this); if(!configGroup.exists()) { return; } document->readSessionConfig(configGroup, QSet() << "SkipUrl"); } void KileProjectItem::saveDocumentSettings(KTextEditor::Document *document) { KConfigGroup configGroup = m_project->configGroupForItemDocumentSettings(this); document->writeSessionConfig(configGroup, QSet() << "SkipUrl"); } void KileProjectItem::print(int level) { QString str; str.fill('\t', level); KILE_DEBUG_MAIN << str << "+" << url().fileName(); if (firstChild()) { firstChild()->print(++level); } if (sibling()) { sibling()->print(level); } } void KileProjectItem::allChildren(QList *list) const { KileProjectItem *item = firstChild(); // KILE_DEBUG_MAIN << "\tKileProjectItem::allChildren(" << list->count() << ")"; while(item != Q_NULLPTR) { list->append(item); // KILE_DEBUG_MAIN << "\t\tappending " << item->url().fileName(); item->allChildren(list); item = item->sibling(); } } void KileProjectItem::setInfo(KileDocument::TextInfo *docinfo) { m_docinfo = docinfo; if(docinfo) { connect(docinfo,SIGNAL(urlChanged(KileDocument::Info*, const QUrl &)), this, SLOT(slotChangeURL(KileDocument::Info*, const QUrl &))); connect(docinfo,SIGNAL(depChanged()), m_project, SLOT(buildProjectTree())); } } void KileProjectItem::changeURL(const QUrl &url) { // don't allow empty URLs if(!url.isEmpty() && m_url != url) { m_url = url; emit(urlChanged(this)); } } void KileProjectItem::slotChangeURL(KileDocument::Info*, const QUrl &url) { changeURL(url); } /* * KileProject */ // for creating an empty project KileProject::KileProject(const QString& name, const QUrl &url, KileDocument::Extensions *extensions) : QObject(Q_NULLPTR), m_invalid(false), m_masterDocument(QString()), m_useMakeIndexOptions(false), m_config(Q_NULLPTR), m_guiConfig(Q_NULLPTR), m_extmanager(extensions) { m_name = name; init(url); //create the project file KConfigGroup configGroup = m_config->group("General"); configGroup.writeEntry("name", m_name); configGroup.writeEntry("kileprversion", KILE_PROJECTFILE_VERSION); configGroup.writeEntry("kileversion", kileFullVersion); load(); } // for opening an existing project, 'load()' still has to be called separately! KileProject::KileProject(const QUrl &url, KileDocument::Extensions *extensions) : QObject(Q_NULLPTR), m_invalid(false), m_masterDocument(QString()), m_useMakeIndexOptions(false), m_config(Q_NULLPTR), m_guiConfig(Q_NULLPTR), m_extmanager(extensions) { init(url); } KileProject::~KileProject() { KILE_DEBUG_MAIN << "DELETING KILEPROJECT " << m_projecturl.url(); emit(aboutToBeDestroyed(this)); delete m_guiConfig; delete m_config; for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { delete *it; } } void KileProject::init(const QUrl &url) { m_projecturl = KileDocument::Manager::symlinkFreeURL(url); m_baseurl = m_projecturl.adjusted(QUrl::RemoveFilename); KILE_DEBUG_MAIN << "KileProject m_baseurl = " << m_baseurl.toLocalFile(); m_config = new KConfig(m_projecturl.toLocalFile(), KConfig::SimpleConfig); } void KileProject::setLastDocument(const QUrl &url) { if (item(url) != 0) { m_lastDocument = KileDocument::Manager::symlinkFreeURL(url); } } void KileProject::setExtensions(KileProjectItem::Type type, const QString & ext) { if (type == KileProjectItem::ProjectFile || type >= KileProjectItem::Other) { qWarning() << "ERROR: invalid project item type:" << type; return; } // first we take all standard extensions QStringList standardExtList; if(type == KileProjectItem::Source) { standardExtList = (m_extmanager->latexDocuments()).split(' '); } else if(type == KileProjectItem::Package) { standardExtList = (m_extmanager->latexPackages()).split(' '); } else if(type == KileProjectItem::Image) { standardExtList = (m_extmanager->images()).split(' '); } else if(type == KileProjectItem::Bibliography) { standardExtList = (m_extmanager->bibtex()).split(' '); } // now we scan user-defined list and accept all extension, // except standard extensions of course QString userExt; if(!ext.isEmpty()) { QStringList userExtList; QStringList::ConstIterator it; QStringList list = ext.split(' '); for(it = list.constBegin(); it != list.constEnd(); ++it) { // some tiny extension checks if((*it).length() < 2 || (*it)[0] != '.') { continue; } // some of the old definitions are wrong, so we test them all if(type == KileProjectItem::Source || type == KileProjectItem::Package) { if(!(m_extmanager->isLatexDocument(*it) || m_extmanager->isLatexPackage(*it))) { standardExtList << (*it); userExtList << (*it); } } else if(type == KileProjectItem::Image) { if(!m_extmanager->isImage(*it)) { standardExtList << (*it); userExtList << (*it); } } else if(type == KileProjectItem::Bibliography) { if(!m_extmanager->isBibFile(*it)) { standardExtList << (*it); userExtList << (*it); } } } if(userExtList.count() > 0) { userExt = userExtList.join(" "); } } // now we build a regular expression for all extensions // (used to search for a filename with a valid extension) QString pattern = standardExtList.join("|"); pattern.replace('.', "\\."); pattern = '('+ pattern +")$"; // and save it m_reExtensions[type-1].setPattern(pattern); // if the list of user-defined extensions has changed // we save the new value and (re)build the project tree if (m_extensions[type-1] != userExt) { m_extensions[type-1] = userExt; buildProjectTree(); } } void KileProject::setDefaultGraphicExt(const QString & ext){ m_defGraphicExt = ext; } const QString & KileProject::defaultGraphicExt(){ return m_defGraphicExt; } void KileProject::setType(KileProjectItem *item) { if(item->path().right(7) == ".kilepr") { item->setType(KileProjectItem::ProjectFile); return; } bool unknown = true; for(int i = KileProjectItem::Source; i < KileProjectItem::Other; ++i) { if(m_reExtensions[i-1].indexIn(item->url().fileName()) != -1) { item->setType(i); unknown = false; break; } } if(unknown) { item->setType(KileProjectItem::Other); } } void KileProject::readMakeIndexOptions() { QString grp = KileTool::groupFor("MakeIndex", m_config); //get the default value KSharedConfig::Ptr cfg = KSharedConfig::openConfig(); KConfigGroup configGroup = cfg->group(KileTool::groupFor("MakeIndex", KileTool::configName("MakeIndex", cfg.data()))); QString deflt = configGroup.readEntry("options", "'%S'.idx"); if (useMakeIndexOptions() && !grp.isEmpty()) { KConfigGroup makeIndexGroup = m_config->group(grp); QString val = makeIndexGroup.readEntry("options", deflt); if ( val.isEmpty() ) val = deflt; setMakeIndexOptions(val); } else { //use default value setMakeIndexOptions(deflt); } } void KileProject::writeUseMakeIndexOptions() { if ( useMakeIndexOptions() ) KileTool::setConfigName("MakeIndex", "Default", m_config); else KileTool::setConfigName("MakeIndex", "", m_config); } QString KileProject::addBaseURL(const QString &path) { KILE_DEBUG_MAIN << "===addBaseURL(const QString & " << path << " )"; if(path.isEmpty()) { return path; } else if(QDir::isAbsolutePath(path)) { return KileDocument::Manager::symlinkFreeURL(QUrl::fromLocalFile(path)).toLocalFile(); } else { return KileDocument::Manager::symlinkFreeURL(QUrl::fromLocalFile(m_baseurl.adjusted(QUrl::StripTrailingSlash).toLocalFile() + '/' + path)).toLocalFile(); } } QString KileProject::removeBaseURL(const QString &path) { if(QDir::isAbsolutePath(path)) { QFileInfo info(path); QString relPath = findRelativePath(path); KILE_DEBUG_MAIN << "removeBaseURL path is" << path << " , relPath is " << relPath; return relPath; } else { return path; } } bool KileProject::appearsToBeValidProjectFile() { if(!m_config->hasGroup("General")) { return false; } KConfigGroup generalGroup = m_config->group("General"); return generalGroup.hasKey("name") && generalGroup.hasKey("kileprversion") && generalGroup.hasKey("kileversion"); } int KileProject::getProjectFileVersion() { KConfigGroup generalGroup = m_config->group("General"); return generalGroup.readEntry("kileprversion", 0); } // WARNING: before calling this method, the project file must be of the current 'kileprversion'! // also assumes that 'm_name' has been set correctly already if this is a fresh (empty) project! bool KileProject::load() { KILE_DEBUG_MAIN << "KileProject: loading..." << endl; if(!ensurePrivateKileDirectoryExists(m_projecturl)) { return false; } delete m_guiConfig; m_guiConfig = new KConfig(getPathForGUISettingsProjectFile(m_projecturl), KConfig::SimpleConfig); //load general settings/options KConfigGroup generalGroup = m_config->group("General"); m_name = generalGroup.readEntry("name", m_name); m_defGraphicExt = generalGroup.readEntry("def_graphic_ext", QString()); QString master = addBaseURL(generalGroup.readEntry("masterDocument", QString())); KILE_DEBUG_MAIN << "masterDoc == " << master; setMasterDocument(master); setExtensions(KileProjectItem::Source, generalGroup.readEntry("src_extensions",m_extmanager->latexDocuments())); setExtensions(KileProjectItem::Package, generalGroup.readEntry("pkg_extensions",m_extmanager->latexPackages())); setExtensions(KileProjectItem::Image, generalGroup.readEntry("img_extensions",m_extmanager->images())); setExtensions(KileProjectItem::Bibliography, generalGroup.readEntry("bib_extensions", m_extmanager->bibtex())); setQuickBuildConfig(KileTool::configName("QuickBuild", m_config)); if( KileTool::configName("MakeIndex",m_config).compare("Default") == 0) { setUseMakeIndexOptions(true); } else { setUseMakeIndexOptions(false); } readMakeIndexOptions(); QUrl url; KileProjectItem *item; - QStringList groups = m_config->groupList(); + const QStringList groups = m_config->groupList(); //retrieve all the project files and create and initialize project items for them - for (int i = 0; i < groups.count(); ++i) { - if (groups[i].left(5) == "item:") { - QString path = groups[i].mid(5); + for (auto group : groups) { + if(!m_config->hasGroup(group)) { // 'group' might have been deleted + continue; // work around bug 384039 + } + if (group.left(5) == "item:") { + QString path = group.mid(5); if (QDir::isAbsolutePath(path)) { url = QUrl::fromLocalFile(path); } else { url = m_baseurl.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + '/' + path); } item = new KileProjectItem(this, KileDocument::Manager::symlinkFreeURL(url)); setType(item); - KConfigGroup configGroup = m_config->group(groups[i]); + KConfigGroup configGroup = m_config->group(group); // path has to be set before we can load it - item->changePath(groups[i].mid(5)); + item->changePath(group.mid(5)); item->load(); connect(item, SIGNAL(urlChanged(KileProjectItem*)), this, SLOT(itemRenamed(KileProjectItem*)) ); } } // only call this after all items are created, otherwise setLastDocument doesn't accept the url KConfigGroup guiGeneralGroup = m_guiConfig->group("General"); setLastDocument(QUrl::fromLocalFile(addBaseURL(guiGeneralGroup.readEntry("lastDocument", QString())))); generalGroup = m_config->group("General"); readBibliographyBackendSettings(generalGroup); KileTool::LivePreviewManager::readLivePreviewStatusSettings(guiGeneralGroup, this); // dump(); return true; } bool KileProject::save() { KILE_DEBUG_MAIN << "KileProject: saving..." <group("General"); KConfigGroup guiGeneralGroup = m_guiConfig->group("General"); generalGroup.writeEntry("name", m_name); generalGroup.writeEntry("kileprversion", KILE_PROJECTFILE_VERSION); generalGroup.writeEntry("kileversion", kileFullVersion); generalGroup.writeEntry("def_graphic_ext", m_defGraphicExt); KILE_DEBUG_MAIN << "KileProject::save() masterDoc = " << removeBaseURL(m_masterDocument); generalGroup.writeEntry("masterDocument", removeBaseURL(m_masterDocument)); guiGeneralGroup.writeEntry("lastDocument", removeBaseURL(m_lastDocument.toLocalFile())); writeBibliographyBackendSettings(generalGroup); KileTool::LivePreviewManager::writeLivePreviewStatusSettings(guiGeneralGroup, this); writeConfigEntry("src_extensions",m_extmanager->latexDocuments(),KileProjectItem::Source); writeConfigEntry("pkg_extensions",m_extmanager->latexPackages(),KileProjectItem::Package); writeConfigEntry("img_extensions",m_extmanager->images(),KileProjectItem::Image); writeConfigEntry("bib_extensions", m_extmanager->bibtex(), KileProjectItem::Bibliography); // only to avoid problems with older versions generalGroup.writeEntry("src_extIsRegExp", false); generalGroup.writeEntry("pkg_extIsRegExp", false); generalGroup.writeEntry("img_extIsRegExp", false); for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { (*it)->save(); } KileTool::setConfigName("QuickBuild", quickBuildConfig(), m_config); writeUseMakeIndexOptions(); if(useMakeIndexOptions()) { QString grp = KileTool::groupFor("MakeIndex", m_config); if(grp.isEmpty()) { grp = "Default"; } KConfigGroup configGroup = m_config->group(grp); configGroup.writeEntry("options", makeIndexOptions()); } m_config->sync(); m_guiConfig->sync(); // dump(); return true; } void KileProject::writeConfigEntry(const QString &key, const QString &standardExt, KileProjectItem::Type type) { KConfigGroup generalGroup = m_config->group("General"); QString userExt = extensions(type); if(userExt.isEmpty()) { generalGroup.writeEntry(key, standardExt); } else { generalGroup.writeEntry(key, standardExt + ' ' + extensions(type)); } } KConfigGroup KileProject::configGroupForItem(KileProjectItem *item, ConfigScope scope) const { KConfig* cfgObject = (scope == GUIFile ? m_guiConfig : m_config); return cfgObject->group("item:" + item->path()); } KConfigGroup KileProject::configGroupForItemDocumentSettings(KileProjectItem *item) const { return m_guiConfig->group("document-settings,item:" + item->path()); } KConfigGroup KileProject::configGroupForItemViewSettings(KileProjectItem *item, int viewIndex) const { return m_guiConfig->group("view-settings,view=" + QString::number(viewIndex) + ",item:" + item->path()); } void KileProject::removeConfigGroupsForItem(KileProjectItem *item) { QString itemString = "item:" + item->path(); - QStringList groupList = m_config->groupList(); - for(QStringList::iterator i = groupList.begin(); i != groupList.end(); ++i) { - QString groupName = *i; + const QStringList groupList = m_config->groupList(); + for(auto groupName : groupList) { + if(!m_config->hasGroup(groupName)) { // 'groupName' might have been deleted + continue; // work around bug 384039 + } if(groupName.indexOf(itemString) >= 0) { m_config->deleteGroup(groupName); } } } static bool isAncestorOf(KileProjectItem *toBeChecked, KileProjectItem *parent) { KileProjectItem *item = parent; while(item != Q_NULLPTR) { if(item == toBeChecked) { return true; } item = item->parent(); } return false; } void KileProject::buildProjectTree() { KILE_DEBUG_MAIN << "==KileProject::buildProjectTree=========================="; //determine the parent doc for each item (TODO:an item can only have one parent, not necessarily true for LaTeX docs) QStringList deps; QString dep; KileProjectItem *itm; QUrl url; //clean first for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { (*it)->setParent(0); } //use the dependencies list of the documentinfo object to determine the parent for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { //set the type correctly (changing m_extensions causes a call to buildProjectTree) setType(*it); KileDocument::Info *docinfo = (*it)->getInfo(); if(docinfo) { QUrl parentUrl = docinfo->url(); if(parentUrl.isLocalFile()) { // strip the file name from 'parentUrl' parentUrl = QUrl::fromUserInput(QFileInfo(parentUrl.path()).path()); } else { parentUrl = m_baseurl; } deps = docinfo->dependencies(); for(int i = 0; i < deps.count(); ++i) { dep = deps[i]; if(m_extmanager->isTexFile(dep)) { url = QUrl::fromLocalFile(KileInfo::checkOtherPaths(parentUrl, dep, KileInfo::texinputs)); } else if(m_extmanager->isBibFile(dep)) { url = QUrl::fromLocalFile(KileInfo::checkOtherPaths(parentUrl, dep, KileInfo::bibinputs)); } itm = item(url); if(itm && (itm->parent() == 0) && !isAncestorOf(itm, *it)) { // avoid circular references if a file should // include itself in a circular way itm->setParent(*it); } } } } //make a list of all the root items (items with parent == 0) m_rootItems.clear(); for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { if((*it)->parent() == Q_NULLPTR) { m_rootItems.append(*it); } } emit(projectTreeChanged(this)); } KileProjectItem* KileProject::item(const QUrl &url) { for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { if((*it)->url() == url) { return *it; } } return Q_NULLPTR; } KileProjectItem* KileProject::item(const KileDocument::Info *info) { for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { KileProjectItem *current = *it; if (current->getInfo() == info) { return current; } } return Q_NULLPTR; } void KileProject::add(KileProjectItem* item) { KILE_DEBUG_MAIN << "KileProject::add projectitem" << item->url().toLocalFile(); setType(item); item->changePath(findRelativePath(item->url())); connect(item, SIGNAL(urlChanged(KileProjectItem*)), this, SLOT(itemRenamed(KileProjectItem*)) ); m_projectItems.append(item); emit projectItemAdded(this, item); // dump(); } void KileProject::remove(KileProjectItem* item) { KILE_DEBUG_MAIN << item->path(); removeConfigGroupsForItem(item); m_projectItems.removeAll(item); emit projectItemRemoved(this, item); // dump(); } void KileProject::itemRenamed(KileProjectItem *item) { KILE_DEBUG_MAIN << "==KileProject::itemRenamed=========================="; KILE_DEBUG_MAIN << "\t" << item->url().fileName(); removeConfigGroupsForItem(item); item->changePath(findRelativePath(item->url())); } QString KileProject::findRelativePath(const QString &path) { return this->findRelativePath(QUrl::fromLocalFile(path)); } QString KileProject::findRelativePath(const QUrl &url) { KILE_DEBUG_MAIN << "QString KileProject::findRelativePath(const QUrl " << url.path() << ")"; if ( m_baseurl.toLocalFile() == url.toLocalFile() ) { return "./"; } const QString path = QDir(m_baseurl.path()).relativeFilePath(url.path()); KILE_DEBUG_MAIN << "relPath is " << path; return path; } bool KileProject::contains(const QUrl &url) { for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { if((*it)->url() == url) { return true; } } return false; } bool KileProject::contains(const KileDocument::Info *info) { for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { if((*it)->getInfo() == info) { return true; } } return false; } KileProjectItem *KileProject::rootItem(KileProjectItem *item) const { //find the root item (i.e. the eldest parent) KileProjectItem *root = item; while(root->parent() != Q_NULLPTR) { root = root->parent(); } //check if this root item is a LaTeX root if(root->getInfo()) { if (root->getInfo()->isLaTeXRoot()) { return root; } else { //if not, see if we can find another root item that is a LaTeX root for(QList::const_iterator it = m_rootItems.begin(); it != m_rootItems.end(); ++it) { KileProjectItem *current = *it; if(current->getInfo() && current->getInfo()->isLaTeXRoot()) { return current; } } } //no LaTeX root found, return previously found root return root; } //root is not a valid item (getInfo() return 0L), return original item return item; } void KileProject::dump() { KILE_DEBUG_MAIN << "KileProject::dump() " << m_name; for(QList::iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { KileProjectItem *item = *it; KILE_DEBUG_MAIN << "item " << item << " has path: " << item->path(); KILE_DEBUG_MAIN << "item->type() " << item->type(); KILE_DEBUG_MAIN << "OpenState: " << item->isOpen(); } } QString KileProject::archiveFileList() const { KILE_DEBUG_MAIN << "KileProject::archiveFileList()"; QString path, list; for(QList::const_iterator it = m_projectItems.begin(); it != m_projectItems.end(); ++it) { if ((*it)->archive()) { list.append(KShell::quoteArg((*it)->path()) + ' '); } } return list; } void KileProject::setMasterDocument(const QString & master){ if(!master.isEmpty()){ QFileInfo fi(master); if(fi.exists()) m_masterDocument = master; else { m_masterDocument.clear(); KILE_DEBUG_MAIN << "setMasterDocument: masterDoc=Q_NULLPTR"; } } else { m_masterDocument.clear(); } emit (masterDocumentChanged(m_masterDocument)); } namespace { void moveConfigGroupKeysAsStrings(KConfig *src, KConfig *dst, const QString& groupName, const QStringList &keysToMove) { KConfigGroup srcGroup(src, groupName); KConfigGroup dstGroup(dst, groupName); for(const QString& key : keysToMove) { if(srcGroup.hasKey(key)) { QString value = srcGroup.readEntry(key, QStringLiteral("")); dstGroup.writeEntry(key, value); srcGroup.deleteEntry(key); } } } void deleteConfigGroupKeys(KConfig *src, const QString& groupName, const QStringList &keysToDelete) { KConfigGroup srcGroup(src, groupName); for(const QString& key : keysToDelete) { srcGroup.deleteEntry(key); } } } bool KileProject::migrateProjectFileToCurrentVersion() { if(getProjectFileVersion() < KILE_PROJECTFILE_VERSION) { return migrateProjectFileToVersion3(); } return true; } bool KileProject::migrateProjectFileToVersion3() { KILE_DEBUG_MAIN << "Migrating project file" << m_projecturl << "to version 3"; // (1) Every config group starting with "document-settings," or "view-settings," will be moved to the GUI config file // (2) In every group named "item:..." the keys "column" and "line" are deleted // (3) In every group named "item:..." the keys "open" and "order" are moved to a new group of the same name // in the GUI project file // (4) In the "General" group the keys "lastDocument", "kile_livePreviewEnabled", "kile_livePreviewStatusUserSpecified", // "kile_livePreviewTool" are moved to the "General" group in the GUI project file if(!ensurePrivateKileDirectoryExists(m_projecturl)) { return false; } KConfig projectGUIFile(getPathForGUISettingsProjectFile(m_projecturl), KConfig::SimpleConfig); QStringList keysToMoveInItemGroups, keysToDeleteInItemGroups, keysToMoveInGeneralGroup; keysToMoveInItemGroups << QStringLiteral("column") << QStringLiteral("line") << QStringLiteral("open") << QStringLiteral("order"); keysToDeleteInItemGroups << QStringLiteral("column") << QStringLiteral("line"); keysToMoveInGeneralGroup << QStringLiteral("lastDocument") << QStringLiteral("kile_livePreviewEnabled") << QStringLiteral("kile_livePreviewStatusUserSpecified") << QStringLiteral("kile_livePreviewTool"); const QStringList groups = m_config->groupList(); - for(int i = 0; i < groups.count(); ++i) { - const QString& groupName = groups[i]; + for(auto groupName : groups) { + if(!m_config->hasGroup(groupName)) { // 'groupName' might have been deleted + continue; // work around bug 384039 + } // these ones we move completely if(groupName.startsWith(QLatin1String("document-settings,")) || groupName.startsWith(QLatin1String("view-settings,"))) { KConfigGroup oldGroup(m_config, groupName); KConfigGroup guiGroup(&projectGUIFile, groupName); oldGroup.copyTo(&guiGroup); m_config->deleteGroup(groupName); continue; } if(groupName.startsWith(QLatin1String("item:"))) { deleteConfigGroupKeys(m_config, groupName, keysToDeleteInItemGroups); moveConfigGroupKeysAsStrings(m_config, &projectGUIFile, groupName, keysToMoveInItemGroups); } else if(groupName == QLatin1String("General")) { moveConfigGroupKeysAsStrings(m_config, &projectGUIFile, groupName, keysToMoveInGeneralGroup); } } if(!projectGUIFile.sync()) { return false; } KConfigGroup configGroup = m_config->group("General"); configGroup.writeEntry("kileprversion", KILE_PROJECTFILE_VERSION); configGroup.writeEntry("kileversion", kileFullVersion); return m_config->sync(); } diff --git a/src/kilestdactions.cpp b/src/kilestdactions.cpp index 0b478b52..f5ea6bd2 100644 --- a/src/kilestdactions.cpp +++ b/src/kilestdactions.cpp @@ -1,481 +1,496 @@ /************************************************************************** * Copyright (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) * ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kilestdactions.h" #include #include #include #include #include #include "kileactions.h" #include "editorextension.h" namespace KileStdActions { void setupStdTags(KileInfo *ki, const QObject* receiver, KActionCollection *actionCollection, QWidget *parentWidget) { (void) new KileAction::Tag(i18n("Document Class Selection - \\documentclass{}"), i18n("Document Class"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_documentclass", "\\documentclass[10pt]{","}", 21, 0, i18n("\\documentclass[options]{class}\nclass : article,report,book,letter\nsize options : 10pt, 11pt, 12pt\npaper size options: a4paper, a5paper, b5paper, letterpaper, legalpaper, executivepaper\n" "other options: \nlandscape -- selects landscape format; default is portrait. \ntitlepage, notitlepage -- selects if there should be a separate title page.\nleqno -- display equation number on left side of equations; default is right side.\n" "fleqn -- display formulae flush left; default is centered.\nonecolumn, twocolumn -- one or two columns; defaults to one column\noneside, twoside -- selects one- or two-sided layout.\n" )); (void) new KileAction::Tag(i18n("Package Import - \\usepackage{}"), i18n("Package Import"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_usepackage", "\\usepackage{","}", 12, 0, i18n("Any options given in the \\documentclass command that are unknown by the selected document class\n" "are passed on to the packages loaded with \\usepackage.")); (void) new KileAction::Tag(i18n("AMS Packages"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_amspackages","\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n",QString(),0,3,i18n("The principal American Mathematical Society packages")); (void) new KileAction::Tag(i18n("Start Document Body - \\begin{document}"), i18n("Start Document Body"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_document","\\begin{document}\n", "\n\\end{document}", 0,1,i18n("Text is allowed only between \\begin{document} and \\end{document}.\nThe 'preamble' (before \\begin{document} ) may contain declarations only.")); (void) new KileAction::Tag(i18n("Generate Title - \\maketitle"), i18n("Generate Title"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_maketitle","\\maketitle",QString(),10,0,i18n("This command generates a title on a separate title page\n- except in the article class, where the title normally goes at the top of the first page.")); (void) new KileAction::Tag(i18n("Table of Contents - \\tableofcontents"), i18n("Table of Contents"), "view-table-of-contents-ltr", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_tableofcontents","\\tableofcontents",QString(),16,0,i18n("Put this command where you want the table of contents to go")); (void) new KileAction::Tag(i18n("Title Definition - \\title{}"), i18n("Title Definition"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_title","\\title{","}",7,0,i18n( "\\title{text}\nThe \\title command declares text to be the title.\nUse \\\\ to tell LaTeX where to start a new line in a long title.")); (void) new KileAction::Tag(i18n("Author Definition - \\author{}"), i18n("Author Definition"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_author","\\author{","}",8,0,i18n( "\\author{names}\nThe \\author command declares the author(s), where names is a list of authors separated by \\and commands.")); (void) new KileAction::Tag(i18n("Center - \\begin{center}"), i18n("Center"), "format-justify-center", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_center", "\\begin{center}\n","%E\n\\end{center}", 0,1, i18n("Each line must be terminated with the string \\\\.")); (void) new KileAction::Tag(i18n("Align Left - \\begin{flushleft}"), i18n("Align Left"), "format-justify-left", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_flushleft", "\\begin{flushleft}\n","%E\n\\end{flushleft}", 0,1, i18n("Each line must be terminated with the string \\\\.") ); (void) new KileAction::Tag(i18n("Align Right - \\begin{flushright}"), i18n("Align Right"), "format-justify-right", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_flushright", "\\begin{flushright}\n","%E\n\\end{flushright}", 0,1, i18n("Each line must be terminated with the string \\\\.") ); (void) new KileAction::Tag(i18n("Quote - \\begin{quote}"), i18n("Quote"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_quote","\\begin{quote}\n","%E\n\\end{quote} ",0,1,i18n("The text is justified at both margins.\nLeaving a blank line between text produces a new paragraph.") ); (void) new KileAction::Tag(i18n("Quotation - \\begin{quotation}"), i18n("Quotation"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_quotation","\\begin{quotation}\n","%E\n\\end{quotation} ",0,1, i18n("The text is justified at both margins and there is paragraph indentation.\nLeaving a blank line between text produces a new paragraph.") ); (void) new KileAction::Tag(i18n("Verse - \\begin{verse}"), i18n("Verse"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_verse", "\\begin{verse}\n","%E\n\\end{verse} ",0,1,i18n("The verse environment is designed for poetry.\nSeparate the lines of each stanza with \\\\, and use one or more blank lines to separate the stanzas.") ); (void) new KileAction::Tag(i18n("Verbatim - \\begin{verbatim}"), i18n("Verbatim"), "verbatim", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_verbatim","\\begin{verbatim}\n","%E\n\\end{verbatim} ",0,1,i18n("Environment that gets LaTeX to print exactly what you type in.")); (void) new KileAction::Tag(i18n("Bulleted List - \\begin{itemize}"), i18n("Bulleted List"), "itemize", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_itemize","\\begin{itemize}\n%E\\item \n", "\\end{itemize}\n", 6,1,i18n("The itemize environment produces a 'bulleted' list.\nEach item of an itemized list begins with an \\item command.")); (void) new KileAction::Tag(i18n("Enumeration - \\begin{enumerate}"), i18n("Enumeration"), "enumerate", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_enumerate","\\begin{enumerate}\n%E\\item \n","\\end{enumerate}\n", 6,1,i18n("The enumerate environment produces a numbered list.\nEach item of an enumerated list begins with an \\item command.")); (void) new KileAction::Tag(i18n("Description - \\begin{description}"), i18n("Description"), "description", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_description","\\begin{description}\n%E\\item[] \n", "\\end{description}",6,1,i18n("The description environment is used to make labeled lists.\nEach item of the list begins with an \\item[label] command.\nThe 'label' is bold face and flushed right.")); (void) new KileAction::Tag(i18n("Table - \\begin{table}"), i18n("Table"), "table-env", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_table","\\begin{table}\n","%E\n\\caption{}\n\\end{table} ",0,1, i18n("\\begin{table}[placement]\nbody of the table\n\\caption{table title}\n\\end{table}\nTables are objects that are not part of the normal text, and are usually floated to a convenient place.\n" "The optional argument [placement] determines where LaTeX will try to place your table\nh : Here - at the position in the text where the table environment appears\nt : Top - at the top of a text page\nb : Bottom - at the bottom of a text page\n" "p : Page of floats - on a separate float page, which is a page containing no text, only floats.\nThe body of the table is made up of whatever text or LaTeX commands, etc., you wish.\nThe \\caption command allows you to title your table.")); (void) new KileAction::Tag(i18n("Figure - \\begin{figure}"), i18n("Figure"), "figure-env", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_figure" ,"\\begin{figure}\n","%E\n\\caption{}\n\\end{figure} ",0,1, i18n("\\begin{figure}[placement]\nbody of the figure\n\\caption{figure title}\n\\end{figure}\nFigures are objects that are not part of the normal text, and are usually floated to a convenient place.\n" "The optional argument [placement] determines where LaTeX will try to place your figure\nh : Here - at the position in the text where the figure environment appears\nt : Top - at the top of a text page\n" "b : Bottom - at the bottom of a text page\np : Page of floats - on a separate float page, which is a page containing no text, only floats.\nThe body of the figure is made up of whatever text or LaTeX commands, etc., you wish.\nThe \\caption command allows you to title your figure.")); (void) new KileAction::Tag(i18n("Title Page - \\begin{titlepage}"), i18n("Title Page"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_titlepage" ,"\\begin{titlepage}\n","%E\n\\end{titlepage} ",0,1, i18n("\\begin{titlepage}\ntext\n\\end{titlepage}\nThe titlepage environment creates a title page, i.e. a page with no printed page number or heading.")); new KileAction::Tag(i18n("Italics - \\textit{}"), i18n("Italics"), "format-text-italic", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_I), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_textit","\\textit{","}",8,0,i18n("\\textit{italic text}")); new KileAction::Tag(i18n("Slanted - \\textsl{}"), i18n("Slanted"), "slanted", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_A), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_textsl","\\textsl{","}",8,0,i18n("\\textsl{slanted text}")); new KileAction::Tag(i18n("Boldface - \\textbf{}"), i18n("Boldface"), "format-text-bold", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_B), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_textbf","\\textbf{","}",8,0,i18n("\\textbf{boldface text}")); new KileAction::Tag(i18n("Typewriter - \\texttt{}"), i18n("Typewriter"), "typewriter", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_T), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_texttt","\\texttt{","}",8,0,i18n("\\texttt{typewriter text}")); new KileAction::Tag(i18n("Small Caps - \\textsc{}"), i18n("Small Caps"), QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_C), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_textsc","\\textsc{","}",8,0,i18n("\\textsc{small caps text}")); new KileAction::Tag("\\item", QString(), "item", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_H), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_item","\\item ",QString(),6,0, i18n("\\item[label] Hello!")); (void) new KileAction::Tag(i18n("Tabbing - \\begin{tabbing}"), i18n("Tabbing"), "tabbing", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_tabbing" ,"\\begin{tabbing}\n","%E\n\\end{tabbing} ",0,1,i18n("The tabbing environment provides a way to align text in columns.\n\\begin{tabbing}\ntext \\= more text \\= still more text \\= last text \\\\\nsecond row \\> \\> more \\\\\n\\end{tabbing}\nCommands :\n\\= Sets a tab stop at the current position.\n\\> Advances to the next tab stop.\n\\< Allows you to put something to the left of the local margin without changing the margin. Can only be used at the start of the line.\n\\+ Moves the left margin of the next and all the following commands one tab stop to the right\n\\- Moves the left margin of the next and all the following commands one tab stop to the left\n\\' Moves everything that you have typed so far in the current column to the right of the previous column, flush against the current column's tab stop. \n\\` Allows you to put text flush right against any tab stop, including tab stop 0\n\\kill Sets tab stops without producing text.\n\\a In a tabbing environment, the commands \\=, \\' and \\` do not produce accents as normal. Instead, the commands \\a=, \\a' and \\a` are used.")); (void) new KileAction::Tag(i18n("Tabular - \\begin{tabular}"), i18n("Tabular"), "tabular", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_tabular" ,"\\begin{tabular}{","}\n%E\n\\end{tabular} ",16,0,i18n("\\begin{tabular}[pos]{cols}\ncolumn 1 entry & column 2 entry ... & column n entry \\\\\n...\n\\end{tabular}\npos : Specifies the vertical position; default is alignment on the center of the environment.\n t - align on top row\n b - align on bottom row\ncols : Specifies the column formatting.\n l - A column of left-aligned items.\n r - A column of right-aligned items.\n c - A column of centered items.\n | - A vertical line the full height and depth of the environment.\n @{text} - this inserts text in every row.\nThe \\hline command draws a horizontal line the width of the table.\nThe \\cline{i-j} command draws horizontal lines across the columns specified, beginning in column i and ending in column j.\nThe \\vline command draws a vertical line extending the full height and depth of its row.")); (void) new KileAction::Tag(i18n("Multicolumn Cells - \\multicolumn"), i18n("Multicolumn Cells"), "multicolumn", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)),actionCollection,"tag_multicolumn","\\multicolumn{","}{}{} ",13,0,i18n("\\multicolumn{cols}{pos}{text}\ncol, specifies the number of columns to span.\npos specifies the formatting of the entry: c for centered, l for flushleft, r for flushright.\ntext specifies what text is to make up the entry.")); (void) new KileAction::Tag(i18n("Horizontal Line - \\hline"), i18n("Horizontal Line"), "hline", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_hline" ,"\\hline ",QString(),7,0,i18n("The \\hline command draws a horizontal line the width of the table.")); (void) new KileAction::Tag(i18n("Vertical Line - \\vline"), i18n("Vertical Line"), "vline", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_vline" ,"\\vline ",QString(),7,0,i18n("The \\vline command draws a vertical line extending the full height and depth of its row.")); (void) new KileAction::Tag(i18n("Horizontal Line Across Columns - \\cline{m-n}"), i18n("Horizontal Line Across Columns"), "cline", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_cline" ,"\\cline{-} ",QString(),7,0,i18n("The \\cline{i-j} command draws horizontal lines across the columns specified, beginning in column i and ending in column j,")); (void) new KileAction::Tag(i18n("New Page - \\newpage"), i18n("New Page"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_newpage","\\newpage ",QString(),9,0,i18n("The \\newpage command ends the current page")); (void) new KileAction::Tag(i18n("Line Break - \\linebreak"), i18n("Line Break"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_linebreak","\\linebreak ",QString(),11,0,i18n("The \\linebreak command tells LaTeX to break the current line at the point of the command.")); (void) new KileAction::Tag(i18n("Page Break - \\pagebreak"), i18n("Page Break"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_pagebreak","\\pagebreak ",QString(),11,0,i18n("The \\pagebreak command tells LaTeX to break the current page at the point of the command.")); (void) new KileAction::Tag(i18n("\"Big\" Vertical Space - \\bigskip"), i18n("\"Big\" Vertical Space"), "bigskip", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bigskip","\\bigskip ",QString(),9,0,i18n("The \\bigskip command adds a 'big' vertical space.")); (void) new KileAction::Tag(i18n("\"Medium\" Vertical Space - \\medskip"), i18n("\"Medium\" Vertical Space"), "medskip", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_medskip","\\medskip ",QString(),9,0,i18n("The \\medskip command adds a 'medium' vertical space.")); // includegraphics (dani) (void) new KileAction::Tag(i18n("Image Insertion - \\includegraphics{file}"), i18n("Image Insertion"), "insert-image", QKeySequence("Alt+I, G"),receiver,SLOT(includeGraphics()), actionCollection,"tag_includegraphics",0L); // two new shortcuts (dani) (void) new KileAction::InputTag(ki, i18n("Customizable File Inclusion - \\include{file}"), i18n("Customizable File Inclusion"), "include-file", QKeySequence("Alt+I, F"), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_include", parentWidget, KileAction::KeepHistory | KileAction::ShowBrowseButton | KileAction::AddProjectFile, "\\include{%R","}",9,0, i18n("\\include{file}\nThe \\include command is used in conjunction with the \\includeonly command for selective inclusion of files."),i18n("Type or select a filename: ")); (void) new KileAction::InputTag(ki, i18n("File Inclusion - \\input{file}"), i18n("File Inclusion"), "input-file", QKeySequence("Alt+I, P"), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_input", parentWidget, KileAction::KeepHistory | KileAction::ShowBrowseButton | KileAction::AddProjectFile, "\\input{%R","}",7,0,i18n("\\input{file}\nThe \\input command causes the indicated file to be read and processed, exactly as if its contents had been inserted in the current file at that point."),i18n("Type or select a filename: ")); ToolbarSelectAction *actionstructure_list = new ToolbarSelectAction(i18n("Sectioning"), actionCollection,false); actionCollection->addAction("structure_list", actionstructure_list); actionstructure_list->addAction(new KileAction::InputTag(ki,"&part", QString(), "part", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_part", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\part%A{%R}","\n", 0,1,i18n("\\part{title}\n\\part*{title} : do not include a number and do not make an entry in the table of contents\n"), i18n("&Part"),i18n("No &numbering"))); actionstructure_list->addSeparator(); actionstructure_list->addAction(new KileAction::InputTag(ki,"&chapter", QString(), "chapter", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_chapter", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\chapter%A{%R}","\n", 0,1,i18n("\\chapter{title}\n\\chapter*{title} : do not include a number and do not make an entry in the table of contents\nOnly for 'report' and 'book' class document."), i18n("C&hapter"),i18n("No &numbering"))); actionstructure_list->addAction(new KileAction::InputTag(ki,"§ion", QString(), "section", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_section", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\section%A{%R}","\n", 0,1,i18n("\\section{title}\n\\section*{title} : do not include a number and do not make an entry in the table of contents"), i18n("&Section"),i18n("No &numbering"))); actionstructure_list->addAction(new KileAction::InputTag(ki,"s&ubsection", QString(), "subsection", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_subsection", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\subsection%A{%R}","\n", 0,1,i18n("\\subsection{title}\n\\subsection*{title} : do not include a number and do not make an entry in the table of contents"), i18n("&Subsection"),i18n("No &numbering"))); actionstructure_list->addAction(new KileAction::InputTag(ki,"su&bsubsection", QString(), "subsubsection", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_subsubsection", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\subsubsection%A{%R}","\n", 0,1,i18n("\\subsubsection{title}\n\\subsubsection*{title} : do not include a number and do not make an entry in the table of contents"), i18n("&Subsubsection"),i18n("No &numbering"))); actionstructure_list->addSeparator(); actionstructure_list->addAction(new KileAction::InputTag(ki,"p&aragraph", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_paragraph", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\paragraph%A{%R}","\n", 0,1,i18n("\\paragraph{title}\n\\paragraph*{title} : do not include a number and do not make an entry in the table of contents"), i18n("&Paragraph"),i18n("No &numbering"))); actionstructure_list->addAction(new KileAction::InputTag(ki,"subpa&ragraph", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_subparagraph", parentWidget, KileAction::ShowAlternative|KileAction::ShowLabel , "\\subparagraph%A{%R}","\n", 0,1,i18n("\\subparagraph{title}\n\\subparagraph*{title} : do not include a number and do not make an entry in the table of contents"), i18n("&Subparagraph"),i18n("No &numbering"))); ToolbarSelectAction *actionsize_list = new ToolbarSelectAction(i18n("Size"), actionCollection,false); actionCollection->addAction("size_list", actionsize_list); actionsize_list->addAction(new KileAction::Tag(i18n("tiny"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_tiny", "\\begin{tiny}", "\\end{tiny}", 12, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("scriptsize"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_scriptsize", "\\begin{scriptsize}", "\\end{scriptsize}", 18, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("footnotesize"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_footnotesize", "\\begin{footnotesize}", "\\end{footnotesize}", 20, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("small"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_small", "\\begin{small}", "\\end{small}", 13, 0)); actionsize_list->addSeparator(); actionsize_list->addAction(new KileAction::Tag(i18n("normalsize"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_normalsize", "\\begin{normalsize}", "\\end{normalsize}", 18, 0)); actionsize_list->addSeparator(); actionsize_list->addAction(new KileAction::Tag(i18n("large"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_large", "\\begin{large}", "\\end{large}", 13, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("Large"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_Large", "\\begin{Large}", "\\end{Large}", 13, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("LARGE"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_LARGE", "\\begin{LARGE}", "\\end{LARGE}", 13, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("huge"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_huge", "\\begin{huge}", "\\end{huge}", 12, 0)); actionsize_list->addAction(new KileAction::Tag(i18n("Huge"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_Huge", "\\begin{Huge}", "\\end{Huge}", 12, 0)); ToolbarSelectAction *actionother_list = new ToolbarSelectAction(i18n("Other"), actionCollection,false); actionCollection->addAction("other_list", actionother_list); actionother_list->addAction(new KileAction::Tag("label", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_label", "\\label{","} ",7,0,i18n("\\label{key}"))); actionother_list->addAction(new KileAction::InputTag(ki,"ref", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_ref", parentWidget, KileAction::FromLabelList, "\\ref{%R", "}", 5,0, QString(), i18n("Label") )); actionother_list->addAction(new KileAction::InputTag(ki,"pageref", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_pageref", parentWidget, KileAction::FromLabelList, "\\pageref{%R", "}", 9,0, QString(), i18n("Label") )); actionother_list->addSeparator(); actionother_list->addAction(new KileAction::Tag("index", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_index","\\index{","}",7,0,i18n( "\\index{word}"))); actionother_list->addAction(new KileAction::Tag("footnote", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_footnote", "\\footnote{","}",10,0,i18n( "\\footnote{text}"))); actionother_list->addSeparator(); actionother_list->addAction(new KileAction::InputTag(ki,"cite", QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_cite", parentWidget, KileAction::FromBibItemList, "\\cite{%R", "}", 6,0, i18n("This command generates an in-text citation to the reference associated with the ref entry in the bib file\nYou can open the bib file with Kile to see all the available references"), i18n("Reference"))); // QAction *action = actionCollection->addAction("citeViewBib", receiver, SLOT(citeViewBib())); // action->setText(i18n("cite from ViewBib")); // actionother_list->addAction(action); (void) new KileAction::Tag(i18n("Underline - \\underline{}"), i18n("Underline"), "format-text-underline", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_underline", "\\underline{","}",11); QAction *action = actionCollection->addAction("tag_newline", ki->editorExtension(), SLOT(insertIntelligentNewline())); action->setText(i18n("Smart New Line")); actionCollection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_Return)); action->setIcon(QIcon::fromTheme("smartnewline")); action = actionCollection->addAction("tag_tabulator", ki->editorExtension(), SLOT(insertIntelligentTabulator())); action->setText(i18n("Smart Tabulator")); actionCollection->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::Key_Ampersand)); // new tags (dani 29.01.2005) KActionCollection* ac = actionCollection; // environments (void) new KileAction::Tag(i18n("Abstract - \\begin{abstract}"), i18n("Abstract"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_env_abstract","\\begin{abstract}\n","%E\n\\end{abstract} ",0,1, i18n("\\begin{abstract}\ntext\n\\end{abstract}\nThe abstract environment creates a title page, i.e. a page with no printed page number or heading.")); (void) new KileAction::Tag(i18n("Tabular* - \\begin{tabular*}"), i18n("Tabular*"), "tabular-star", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_env_tabular*","\\begin{tabular*}{}{","}\n%E\n\\end{tabular*}\n",17,0, i18n("\\begin{tabular*}{width}[pos]{cols}\ncolumn 1 entry & column 2 entry ... & column n entry \\\\\n...\n\\end{tabular*}\nThis is an extended version of the tabular environment with an extra parameter for the width. There must be rubber space between columns that can stretch to fill out the specified width.")); (void) new KileAction::Tag(i18n("Minipage - \\begin{minipage}"), i18n("Minipage"), "minipage", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)),ac,"tag_env_minipage","\\begin{minipage}[","]{}\n%E\n\\end{minipage} ",17,0, i18n("The minipage environment is similar to a \\parbox command. It takes the same optional position argument and mandatory width argument. You may use other paragraph-making environments inside a minipage.")); // lists (void) new KileAction::Tag(i18n("Table of Figures - \\listoffigures"), i18n("Table of Figures"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), ac,"tag_listoffigures","\\listoffigures",QString(),14,0, i18n("Put this command where you want the list of figures to go.")); (void) new KileAction::Tag(i18n("Table of Tables - \\listoftables"), i18n("Table of Tables"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_listoftables","\\listoftables",QString(),14,0, i18n("Put this command where you want the list of tables to go.")); (void) new KileAction::Tag(i18n("Generate Index - \\makeindex"), i18n("Generate Index"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_makeindex","\\makeindex",QString(),10,0, i18n("Put this command when you want to generate the raw index.")); (void) new KileAction::Tag(i18n("Print Index - \\printindex"), i18n("Print Index"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_printindex","\\printindex",QString(),11,0, i18n("Put this command when you want to print the formatted index.")); (void) new KileAction::Tag(i18n("Glossary - \\makeglossary"), i18n("Glossary"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_makeglossary","\\makeglossary",QString(),13,0, i18n("Put this command when you want to print a glossary.")); (void) new KileAction::Tag(i18n("Bibliography - \\begin{thebibliography}"), i18n("Bibliography"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), ac,"tag_env_thebibliography" ,"\\begin{thebibliography}{","}\n\n\\end{thebibliography} ",24,0, i18n("\\begin{thebibliography}{widest-label}\n\\bibitem[label]{cite_key}\n...\n\\end{thebibliography}\n\nwidest-label : Text that, when printed, is approximately as wide as the widest item label produces by the \\bibitem commands\n\\bibitem : Specify a bibliography item")); // verbatim code (void) new KileAction::Tag(i18n("Verbatim (show spaces) - \\begin{verbatim*}"), i18n("Verbatim (show spaces)"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)),ac,"tag_env_verbatim*","\\begin{verbatim*}\n","%E\n\\end{verbatim*}\n",0,1, i18n("Environment that gets LaTeX to print exactly what you type in. In this variant, spaces are printed in a special manner.")); (void) new KileAction::Tag(i18n("Embedded Code - \\verb||"), i18n("Embedded Code"), "verb", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)),ac,"tag_verb","\\verb|","|",6,0, i18n("Macro form of the verbatim environment.")); (void) new KileAction::Tag(i18n("Embedded Code (show spaces) - \\verb*||"), i18n("Embedded Code (show spaces)"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)),ac,"tag_verb*","\\verb*|","|",7,0, i18n("Macro form of the verbatim* environment.")); // horizontal/vertical space (void) new KileAction::Tag(i18n("\"Small\" Vertical Space - \\smallskip"), i18n("\"Small\" Vertical Space"), "smallskip", QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), ac,"tag_smallskip","\\smallskip ",QString(),10,0, i18n("The \\smallskip command adds a 'small' vertical space.")); (void) new KileAction::Tag(i18n("\\enskip"), QString(), "enskip", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_enskip", "\\enskip ", QString(), 8); (void) new KileAction::Tag(i18n("Horizontal Variable Space - \\hfill"), i18n("Horizontal Variable Space"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_hfill","\\hfill",QString(),6,0, i18n("The \\hfill fill command produces a \"rubber length\" which can stretch or shrink horizontally. It will be filled with spaces.")); (void) new KileAction::Tag(i18n("Horizontal Dots - \\dotfill"), i18n("Horizontal Dots"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_dotfill","\\dotfill",QString(),8,0, i18n("The \\dotfill command produces a \"rubber length\" that produces dots instead of just spaces.")); (void) new KileAction::Tag(i18n("Horizontal Rule - \\hrulefill"), i18n("Horizontal Rule"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_hrulefill","\\hrulefill",QString(),10,0, i18n("The \\hrulefill fill command produces a \"rubber length\" which can stretch or shrink horizontally. It will be filled with a horizontal rule.")); (void) new KileAction::Tag(i18n("Vertical Variable Space - \\vfill"), i18n("Vertical Variable Space"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_vfill","\\vfill",QString(),6,0, i18n("The \\vfill fill command produces a \"rubber length\" which can stretch or shrink vertically.")); (void) new KileAction::Tag(i18n("Horizontal Space - \\hspace{}"), i18n("Horizontal Space"), "hspace", QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_hspace","\\hspace{","}",8,0, i18n("The \\hspace command adds horizontal space. The length of the space can be expressed in any terms that LaTeX understands, i.e., points, inches, etc. You can add negative as well as positive space with an \\hspace command. Adding negative space is like backspacing.")); (void) new KileAction::Tag(i18n("Horizontal Space (forced) - \\hspace*{}"), i18n("Horizontal Space (forced)"), "hspace-star", QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_hspace*","\\hspace*{","}",9,0, i18n("The \\hspace* command adds horizontal space like the \\hspace command. LaTeX removes horizontal space that comes at the end of a line. If you do not want LaTeX to remove this space, include the optional * argument. Then the space is never removed.")); (void) new KileAction::Tag(i18n("Vertical Space - \\vspace{}"), i18n("Vertical Space"), "vspace", QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_vspace","\\vspace{","}",8,0, i18n("The \\vspace command adds vertical space. The length of the space can be expressed in any terms that LaTeX understands, i.e., points, inches, etc. You can add negative as well as positive space with an \\vspace command.")); (void) new KileAction::Tag(i18n("Vertical Space (forced) - \\vspace*{}"), i18n("Vertical Space (forced)"), "vspace-star", QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)),ac,"tag_vspace*","\\vspace*{","}",9,0, i18n("The \\vspace* command adds vertical space like the \\vspace command. LaTeX removes vertical space that comes at the end of a page. If you do not want LaTeX to remove this space, include the optional * argument. Then the space is never removed.")); // fonts new KileAction::Tag(i18n("Emphasized - \\emph{}"), i18n("Emphasized"), "emph", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_emph","\\emph{","}",6,0,i18n("\\emph{emphasized text}")); new KileAction::Tag(i18n("Strong - \\strong{}"), i18n("Strong"), "strong", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_strong","\\strong{","}",8,0,i18n("\\strong{text}")); (void) new KileAction::Tag(i18n("Roman - \\rmfamily"), i18n("Roman"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_rmfamily", "\\rmfamily", QString(), 9); (void) new KileAction::Tag(i18n("Sans Serif - \\sffamily"), i18n("Sans Serif"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_sffamily", "\\sffamily", QString(), 9); (void) new KileAction::Tag(i18n("Monospace - \\ttfamily"), i18n("Monospace"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_ttfamily", "\\ttfamily", QString(), 9); (void) new KileAction::Tag(i18n("Medium - \\mdseries"), i18n("Medium"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_mdseries", "\\mdseries", QString(), 9); (void) new KileAction::Tag(i18n("Bold - \\bfseries"), i18n("Bold"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_bfseries", "\\bfseries", QString(), 9); (void) new KileAction::Tag(i18n("Upright - \\upshape"), i18n("Upright"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_upshape", "\\upshape", QString(), 8); (void) new KileAction::Tag(i18n("Italic - \\itshape"), i18n("Italic"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_itshape", "\\itshape", QString(), 8); (void) new KileAction::Tag(i18n("Slanted - \\slshape"), i18n("Slanted"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_slshape", "\\slshape", QString(), 8); (void) new KileAction::Tag(i18n("Smallcaps - \\scshape"), i18n("Smallcaps"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_scshape", "\\scshape", QString(), 8); } void setupBibTags(const QObject *receiver, KActionCollection *actionCollection, KActionMenu * menu) { KILE_DEBUG_MAIN << "void setupBibTags(const QObject *receiver, KActionCollection *actionCollection)"; QString filename; if(KileConfig::bibliographyType().isEmpty() || KileConfig::bibliographyType() == QString("bibtex") ) { menu->addAction(new KileAction::Tag(i18n("Bibliography Style Selection - \\bibliographystyle{}"), i18n("Bibliography Style Selection"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bibliographystyle", "\\bibliographystyle{","} ",19,0,i18n("The argument to \\bibliographystyle refers to a file style.bst, which defines how your citations will look\nThe standard styles distributed with BibTeX are:\nalpha : sorted alphabetically. Labels are formed from name of author and year of publication.\nplain : sorted alphabetically. Labels are numeric.\nunsrt : like plain, but entries are in order of citation.\nabbrv : like plain, but more compact labels."))); menu->addAction(new KileAction::Tag(i18n("Bibliography Generation - \\bibliography{}"), i18n("Bibliography Generation"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bibliography","\\bibliography{%S", "}\n",14, 0,i18n("The argument to \\bibliography refers to the bib file (without extension)\nwhich should contain your database in BibTeX format.\nKile inserts automatically the base name of the TeX file"))); menu->addSeparator(); filename = QStandardPaths::locate(QStandardPaths::DataLocation, "bibtexentries.rc"); } else if(KileConfig::bibliographyType() == QString("biblatex")){ menu->addAction(new KileAction::Tag(i18n("Load Biblatex Package - \\usepackage{biblatex}"), i18n("Load Biblatex Package"), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bibliographyPackage", "\\usepackage{biblatex}\n",QString(),21,0,i18n("This includes the package biblatex"))); menu->addAction(new KileAction::Tag(i18n("Bibliography Generation - \\bibliography{}"), i18n("Bibliography Generation"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bibliography","\\bibliography{%S", "}\n",14, 0,i18n("The argument to \\bibliography refers to the bib file (without extension)\nwhich should contain your database in BibTeX format.\nKile inserts automatically the base name of the TeX file"))); menu->addAction(new KileAction::Tag(i18n("Print Bibliography"), QString(), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_printbibliography", "\\printbibliography",QString(),18,0,i18n("Prints the complete bibliography"))); menu->addAction(new KileAction::Tag(i18n("Print Bibliography by Section"), QString(), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bibliographyBySection", "\\bibbysection[","]",14,0,i18n("Print the bibliography for each section"))); menu->addAction(new KileAction::Tag(i18n("Print List of Shorthands"), QString(), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bibliographyShortHands", "\\printshorthands",QString(),16,0,QString())); menu->addSeparator(); /* use this to insert more menu->addAction(new KileAction::Tag(i18n(""), QKeySequence(), receiver,SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_", "\\",QString(),,0,i18n(""))); Load Biblatex-Package - \usepackage{biblatex} Bibliography File - \bibliography{} Print Bibliography - \printbibliography Print Bibliography by Section - \bibbysection[] Print List of Shorthands - \printshorthands */ filename = QStandardPaths::locate(QStandardPaths::DataLocation, "biblatexentries.rc"); } else { filename.clear(); } if(filename.isEmpty()){ KILE_DEBUG_MAIN << "found no filename" << endl; return; } KConfig *bibCfg = new KConfig(filename, KConfig::SimpleConfig); if(bibCfg == Q_NULLPTR ) return; - QStringList groupList = bibCfg->groupList(); - - if( groupList.count() == 0 ) - return; + const QStringList groupList = bibCfg->groupList(); + + // check if a non-deleted group exists + // groupList.count() == 0 is not enough due to bug 384039 + { + bool allDeleted = false; + for(auto group : groupList) { + if(bibCfg->hasGroup(group)) { + allDeleted = false; + break; + } + } + if(allDeleted) { + return; + } + } QString name, tag, internalName, keys, key; QStringList keyList, optKeyList, altKeyList; QString altText, optText, compText; - for(QList::iterator it = groupList.begin(); it != groupList.end(); ++it) { + for(auto group : groupList) { + if(!bibCfg->hasGroup(group)) { // 'group' might have been deleted + continue; // work around bug 384039 + } altKeyList.clear(); keyList.clear(); optKeyList.clear(); - KConfigGroup grp = bibCfg->group(*it); + KConfigGroup grp = bibCfg->group(group); // KILE_DEBUG_MAIN << "group " << grp.name(); tag = grp.name(); name = grp.readEntry(QString("name")); internalName = grp.readEntry(QString("internalName")); keyList = grp.readEntry(QString("key")).split(',', QString::SkipEmptyParts); altKeyList = grp.readEntry(QString("altkey")).split(',', QString::SkipEmptyParts); optKeyList = grp.readEntry(QString("optkey")).split(',', QString::SkipEmptyParts); // KILE_DEBUG_MAIN << "length(keys)=" << keyList.count() << ", length(altkeys)=" << altKeyList.count() << ", length(optkeys)=" << optKeyList.count(); // KILE_DEBUG_MAIN << "tag=" << tag << ", name=" << name << ", internalName=" << internalName; keys = QString("@%1{,\n").arg(tag); int length = keys.length() - 2; // do some trimming name = name.trimmed(); internalName = "tag_bib_" + internalName.trimmed(); tag = tag.trimmed(); for(QList::iterator it = keyList.begin(); it != keyList.end(); ++it) { key = (*it).trimmed(); key = QString(" %1 = {},\n").arg(key); keys.append(key); // KILE_DEBUG_MAIN << "key" << key ; } for(QList::iterator it = altKeyList.begin(); it != altKeyList.end(); ++it) { key = (*it).trimmed(); key = QString(" ALT%1 = {},\n").arg(key); keys.append(key); // KILE_DEBUG_MAIN << "altkey" << key ; } for(QList::iterator it = optKeyList.begin(); it != optKeyList.end(); ++it) { key = (*it).trimmed(); key = QString(" OPT%1 = {},\n").arg(key); keys.append(key); // KILE_DEBUG_MAIN << "optKey" << key; } keys.append("}\n"); altText = i18n("ALT.... : you have the choice between these two fields\n"); optText = i18n("OPT.... : optional fields (use the 'Clean' command to remove them)"); compText = i18n("Bib fields - %1\n",name); if( altKeyList.count() > 1 ) { compText.append(altText); } if( optKeyList.count() > 1 ) { compText.append(optText); } menu->addAction(new KileAction::Tag(name, QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,internalName,keys,QString(),length,0,compText)); } } void setupMathTags(const QObject *receiver, KActionCollection *actionCollection) { (void) new KileAction::Tag(i18n("\\mathrm{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathrm","\\mathrm{","}",8); (void) new KileAction::Tag(i18n("\\mathit{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathit" ,"\\mathit{","}",8); (void) new KileAction::Tag(i18n("\\mathbf{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathbf" ,"\\mathbf{","}",8); (void) new KileAction::Tag(i18n("\\mathsf{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathsf" ,"\\mathsf{","}",8); (void) new KileAction::Tag(i18n("\\mathtt{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathtt" ,"\\mathtt{","}",8); (void) new KileAction::Tag(i18n("\\mathcal{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathcal" ,"\\mathcal{","}",9); (void) new KileAction::Tag(i18n("\\mathbb{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathbb" ,"\\mathbb{","}",8); (void) new KileAction::Tag(i18n("\\mathfrak{}"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathfrak" ,"\\mathfrak{","}",10); (void) new KileAction::Tag(i18n("\\acute{}"), QString(), "acute", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_acute", "\\acute{","}",7); (void) new KileAction::Tag(i18n("\\grave{}"), QString(), "grave", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_grave", "\\grave{","}", 7); (void) new KileAction::Tag(i18n("\\tilde{}"), QString(), "tilde", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_tilde", "\\tilde{","}", 7); (void) new KileAction::Tag(i18n("\\bar{}"), QString(), "bar", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_bar", "\\bar{","}", 5); (void) new KileAction::Tag(i18n("\\vec{}"), QString(), "vec", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_vec", "\\vec{","}", 5); (void) new KileAction::Tag(i18n("\\hat{}"), QString(), "hat", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_hat", "\\hat{","}", 5); (void) new KileAction::Tag(i18n("\\check{}"), QString(), "check", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_check", "\\check{","}", 7); (void) new KileAction::Tag(i18n("\\breve{}"), QString(), "breve", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_breve", "\\breve{","}", 7); (void) new KileAction::Tag(i18n("\\dot{}"), QString(), "dot", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_dot", "\\dot{","}", 5); (void) new KileAction::Tag(i18n("\\ddot{}"), QString(), "ddot", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_ddot", "\\ddot{","}", 6); (void) new KileAction::Tag(i18n("Small Space"), QString(), "thinspace", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_space_small", "\\,", QString(), 2); (void) new KileAction::Tag(i18n("Medium Space"), QString(), "medspace", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_space_medium", "\\:", QString(),2); (void) new KileAction::Tag(i18n("Large Space"), QString(), "bigspace", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_space_large", "\\;", QString(),2); (void) new KileAction::Tag(i18n("\\quad"), QString(), "quad", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_quad", "\\quad ", QString(), 6); (void) new KileAction::Tag(i18n("\\qquad"), QString(), "qquad", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_qquad", "\\qquad ", QString(), 7); (void) new KileAction::Tag(i18n("Math Mode - $...$"), i18n("Math Mode"), "mathmode", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_M), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_mathmode","$","$",1); (void) new KileAction::Tag(i18n("Displaymath Mode - \\[...\\]"), i18n("Displaymath Mode"), "displaymathmode", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_E), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_equation", "\\[","\\]", 2); (void) new KileAction::Tag(i18n("Equation - \\begin{equation}"), i18n("Equation"), "equation", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_equation","\\begin{equation}\n","%E\n\\end{equation} ",0,1); (void) new KileAction::Tag(i18n("Subscript - _{}"), i18n("Subscript"), "format-text-subscript", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_D), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_subscript","_{","}",2); (void) new KileAction::Tag(i18n("Superscript - ^{}"), i18n("Superscript"), "format-text-superscript", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_U), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_superscript","^{","}",2); (void) new KileAction::Tag(i18n("Normal Fraction - \\frac{}{}"), i18n("Normal Fraction"), "smallfrac", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_F), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_frac", "\\frac{","}{}",6); (void) new KileAction::Tag(i18n("Displaystyle Fraction - \\dfrac{}{}"), i18n("Displaystyle Fraction"), "dfrac", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_Q), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), actionCollection,"tag_dfrac", "\\dfrac{","}{}", 7); (void) new KileAction::Tag(i18n("Textstyle Fraction - \\tfrac{}{}"), i18n("Textstyle Fraction"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), actionCollection, "tag_tfrac", "\\tfrac{", "}{}", 7); (void) new KileAction::Tag(i18n("Square Root - \\sqrt{}"), i18n("Square Root"), "sqrt", QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_S), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_sqrt", "\\sqrt{","}", 6); (void) new KileAction::Tag(i18n("\\left"), QString(), QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_L), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_left", "\\left", QString(), 5); (void) new KileAction::Tag(i18n("\\right"), QString(), QKeySequence(Qt::ALT+Qt::SHIFT+Qt::Key_R), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_right", "\\right", QString(), 6); (void) new KileAction::Tag(i18n("Array - \\begin{array}"), i18n("Array"), "array", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection,"tag_env_array", "\\begin{array}{}\n", "%E\n\\end{array}", 14, 0, i18n("\\begin{array}{col1col2...coln}\ncolumn 1 entry & column 2 entry ... & column n entry \\\\ \n...\n\\end{array}\nEach column, coln, is specified by a single letter that tells how items in that column should be formatted.\n" " c -- for centered \n l -- for flush left \n r -- for flush right\n")); ToolbarSelectAction *actionleft_list = new ToolbarSelectAction(i18n("Left Delimiter"), actionCollection,false); actionCollection->addAction("left_list", actionleft_list); actionleft_list->addAction(new KileAction::Tag(i18n("left ("), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_(", "\\left( ", QString(), 7, 0)); actionleft_list->addAction(new KileAction::Tag(i18n("left ["), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_[", "\\left[ ", QString(), 7, 0)); actionleft_list->addAction(new KileAction::Tag(i18n("left {"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_{", "\\left\\lbrace ", QString(), 14, 0)); actionleft_list->addAction(new KileAction::Tag(i18n("left <"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_<", "\\left\\langle ", QString(), 14, 0)); actionleft_list->addSeparator(); actionleft_list->addAction(new KileAction::Tag(i18n("left )"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_)", "\\left) ", QString(), 7, 0)); actionleft_list->addAction(new KileAction::Tag(i18n("left ]"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_]", "\\left] ", QString(), 7, 0)); actionleft_list->addAction(new KileAction::Tag(i18n("left }"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_}", "\\left\\rbrace ", QString(), 14, 0)); actionleft_list->addAction(new KileAction::Tag(i18n("left >"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_>", "\\left\\rangle ", QString(), 14, 0)); actionleft_list->addSeparator(); actionleft_list->addAction(new KileAction::Tag(i18n("left ."), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_left_.", "\\left. ", QString(), 7, 0)); ToolbarSelectAction *actionright_list = new ToolbarSelectAction(i18n("Right Delimiter"), actionCollection,false); actionCollection->addAction("right_list", actionright_list); actionright_list->addAction(new KileAction::Tag(i18n("right )"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_)", "\\right) ", QString(), 8, 0)); actionright_list->addAction(new KileAction::Tag(i18n("right ]"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_]", "\\right] ", QString(), 8, 0)); actionright_list->addAction(new KileAction::Tag(i18n("right }"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_}", "\\right\\rbrace ", QString(), 14, 0)); actionright_list->addAction(new KileAction::Tag(i18n("right >"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_>", "\\right\\rangle ", QString(), 14, 0)); actionright_list->addSeparator(); actionright_list->addAction(new KileAction::Tag(i18n("right ("), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_(", "\\right( ", QString(), 8, 0)); actionright_list->addAction(new KileAction::Tag(i18n("right ["), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_[", "\\right[ ", QString(), 8, 0)); actionright_list->addAction(new KileAction::Tag(i18n("right {"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_{", "\\right\\lbrace ", QString(), 14, 0)); actionright_list->addAction(new KileAction::Tag(i18n("right <"), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_<", "\\right\\langle ", QString(), 14, 0)); actionright_list->addSeparator(); actionright_list->addAction(new KileAction::Tag(i18n("right ."), QString(), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), actionCollection, "tag_right_.", "\\right. ", QString(), 8, 0)); // new math tags (dani 29.01.2005) KActionCollection* ac = actionCollection; (void) new KileAction::Tag(i18n("Normal Binomial - \\binom{}{}"), i18n("Normal Binomial"), "binom", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_binom", "\\binom{","}{}", 7); (void) new KileAction::Tag(i18n("Displaystyle Binomial - \\dbinom{}{}"), i18n("Displaystyle Binomial"), QKeySequence(), receiver,SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_dbinom", "\\dbinom{","}{}", 8); (void) new KileAction::Tag(i18n("Textstyle Binomial - \\tbinom{}{}"), i18n("Textstyle Binomial"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_tbinom", "\\tbinom{","}{}", 8); (void) new KileAction::Tag(i18n("N-th Root - \\sqrt[]{}"), i18n("N-th Root"), "nroot", QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_nroot", "\\sqrt[]{","}", 6); (void) new KileAction::Tag(i18n("Left-Right () - \\left(..\\right)"), i18n("Left-Right ()"), "lr", QKeySequence(Qt::ALT+Qt::Key_ParenLeft), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_leftright", "\\left( \\right)", QString(), 7); (void) new KileAction::Tag(i18n("Extendable Left Arrow - \\xleftarrow{}"), i18n("Extendable Left Arrow"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_xleftarrow", "\\xleftarrow{","}", 12); (void) new KileAction::Tag(i18n("Extendable Right Arrow - \\xrightarrow{}"), i18n("Extendable Right Arrow"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_xrightarrow", "\\xrightarrow{","}", 13); (void) new KileAction::Tag(i18n("Boxed Formula - \\boxed{}"), i18n("Boxed Formula"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_boxed", "\\boxed{","}", 7); (void) new KileAction::Tag(i18n("bigl - \\bigl"), i18n("bigl"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_bigl", "\\bigl",QString(), 5); (void) new KileAction::Tag(i18n("Bigl - \\Bigl"), i18n("Bigl"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_Bigl", "\\Bigl",QString(), 5); (void) new KileAction::Tag(i18n("biggl - \\biggl"), i18n("biggl"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_biggl", "\\biggl",QString(), 6); (void) new KileAction::Tag(i18n("Biggl - \\Biggl"), i18n("Biggl"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_Biggl", "\\Biggl",QString(), 6); (void) new KileAction::Tag(i18n("bigr - \\bigr"), i18n("bigr"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_bigr", "\\bigr",QString(), 5); (void) new KileAction::Tag(i18n("Bigr - \\Bigr"), i18n("Bigr"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_Bigr", "\\Bigr",QString(), 5); (void) new KileAction::Tag(i18n("biggr - \\biggr"), i18n("biggr"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_biggr", "\\biggr",QString(), 6); (void) new KileAction::Tag(i18n("Biggr - \\Biggr"), i18n("Biggr"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_Biggr", "\\Biggr",QString(), 6); // text in mathmode (void) new KileAction::Tag(i18n("Text in Mathmode - \\text{}"), i18n("Text in Mathmode"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_text", "\\text{","}", 6); (void) new KileAction::Tag(i18n("Intertext - \\intertext{}"), i18n("Intertext"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)), ac,"tag_intertext", "\\intertext{","}\n", 11); // math environments (void) new KileAction::Tag(i18n("Displaymath - \\begin{displaymath}"), i18n("Displaymath"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_env_displaymath","\\begin{displaymath}\n","%E\n\\end{displaymath}\n",0,1); (void) new KileAction::Tag(i18n("Equation (not numbered) - \\begin{equation*}"), i18n("Equation (not numbered)"), QKeySequence(), receiver, SLOT(insertTag(const KileAction::TagData&)), ac,"tag_env_equation*","\\begin{equation*}\n","%E\n\\end{equation*}\n",0,1); // AMS environments (void) new KileAction::Tag(i18n("Multline - \\begin{multline}"), i18n("Multline"), "multline", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_multline","\\begin{multline}\n","%E\n\\end{multline}\n", 0,1); (void) new KileAction::Tag(i18n("Multline* - \\begin{multline*}"), i18n("Multline*"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_multline*","\\begin{multline*}\n","%E\n\\end{multline*}\n", 0,1); (void) new KileAction::Tag(i18n("Split - \\begin{split}"), i18n("Split"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_split","\\begin{split}\n","%E\n\\end{split}\n", 0,1); (void) new KileAction::Tag(i18n("Gather - \\begin{gather}"), i18n("Gather"), "gather", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_gather","\\begin{gather}\n","%E\n\\end{gather}\n", 0,1); (void) new KileAction::Tag(i18n("Gather* - \\begin{gather*}"), i18n("Gather*"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_gather*","\\begin{gather*}\n","%E\n\\end{gather*}\n", 0,1); (void) new KileAction::Tag(i18n("Align - \\begin{align}"), i18n("Align"), "align", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_align","\\begin{align}\n","%E\n\\end{align}\n", 0,1); (void) new KileAction::Tag(i18n("Align* - \\begin{align*}"), i18n("Align*"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_align*","\\begin{align*}\n","%E\n\\end{align*}\n", 0,1); (void) new KileAction::Tag(i18n("Flalign - \\begin{flalign}"), i18n("Flalign"), "flalign", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_flalign","\\begin{flalign}\n","%E\n\\end{flalign}\n", 0,1); (void) new KileAction::Tag(i18n("Flalign* - \\begin{flalign*}"), i18n("Flalign*"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_flalign*","\\begin{flalign*}\n","%E\n\\end{flalign*}\n", 0,1); (void) new KileAction::Tag(i18n("Alignat - \\begin{alignat}"), i18n("Alignat"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_alignat","\\begin{alignat}{","}\n%E\n\\end{alignat}\n", 16,0); (void) new KileAction::Tag(i18n("Alignat* - \\begin{alignat*}"), i18n("Alignat*"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_alignat*","\\begin{alignat*}{","}\n%E\n\\end{alignat*}\n", 17,0); (void) new KileAction::Tag(i18n("Aligned - \\begin{aligned}"), i18n("Aligned"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_aligned","\\begin{aligned}\n","%E\n\\end{aligned}\n", 0,1); (void) new KileAction::Tag(i18n("Gathered - \\begin{gathered}"), i18n("Gathered"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_gathered","\\begin{gathered}\n","%E\n\\end{gathered}\n", 0,1); (void) new KileAction::Tag(i18n("Alignedat - \\begin{alignedat}"), i18n("Alignedat"), QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_alignedat","\\begin{alignedat}\n","%E\n\\end{alignedat}\n", 0,1); (void) new KileAction::Tag(i18n("Cases - \\begin{cases}"), i18n("Cases"), "cases", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_cases","\\begin{cases}\n","%E\n\\end{cases}\n", 0,1); (void) new KileAction::Tag(i18n("matrix - \\begin{matrix}"), i18n("matrix"), "matrix", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_matrix","\\begin{matrix}\n","%E\n\\end{matrix}\n", 0,1); (void) new KileAction::Tag(i18n("pmatrix - \\begin{pmatrix}"), i18n("pmatrix"), "pmatrix", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_pmatrix","\\begin{pmatrix}\n","%E\n\\end{pmatrix}\n", 0,1); (void) new KileAction::Tag(i18n("vmatrix - \\begin{vmatrix}"), i18n("vmatrix"), "vmatrix", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_vmatrix","\\begin{vmatrix}\n","%E\n\\end{vmatrix}\n", 0,1); (void) new KileAction::Tag(i18n("Vmatrix - \\begin{Vmatrix}"), i18n("Vmatrix"), "VVmatrix", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_VVmatrix","\\begin{Vmatrix}\n","%E\n\\end{Vmatrix}\n", 0,1); (void) new KileAction::Tag(i18n("bmatrix - \\begin{bmatrix}"), i18n("bmatrix"), "bmatrix", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_bmatrix","\\begin{bmatrix}\n","%E\n\\end{bmatrix}\n", 0,1); (void) new KileAction::Tag(i18n("Bmatrix - \\begin{Bmatrix}"), i18n("Bmatrix"), "BBmatrix", QKeySequence(), receiver, SLOT(insertAmsTag(const KileAction::TagData&)),ac,"tag_env_BBmatrix","\\begin{Bmatrix}\n","%E\n\\end{Bmatrix}\n", 0,1); } } diff --git a/src/kiletoolmanager.cpp b/src/kiletoolmanager.cpp index cdc43285..31704a6e 100644 --- a/src/kiletoolmanager.cpp +++ b/src/kiletoolmanager.cpp @@ -1,802 +1,817 @@ /************************************************************************************** Copyright (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net) 2011-2017 by Michel Ludwig (michel.ludwig@kdemail.net) **************************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kiletoolmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include "configurationmanager.h" #include "errorhandler.h" #include "kileconfig.h" #include "kiledebug.h" #include "kiledocmanager.h" #include "kileinfo.h" #include "kileproject.h" #include "kilestdtools.h" #include "kiletool_enums.h" #include "parser/parsermanager.h" #include "widgets/logwidget.h" #include "widgets/outputview.h" #include "widgets/sidebar.h" namespace KileTool { QueueItem::QueueItem(Base *tool, bool block) : m_tool(tool), m_bBlock(block) { } QueueItem::~QueueItem() { } Base* Queue::tool() const { if(count() > 0 && head()) { return head()->tool(); } else { return 0; } } bool Queue::shouldBlock() const { if(count() > 0 && head()) { return head()->shouldBlock(); } else { return false; } } void Queue::enqueueNext(QueueItem *item) { if(count() < 2) { enqueue(item); } else { QueueItem *headitem = dequeue(); Queue *oldqueue = new Queue(*this); clear(); KILE_DEBUG_MAIN << "\tenqueueing: " << headitem->tool()->name() << endl; enqueue(headitem); KILE_DEBUG_MAIN << "\tenqueueing: " << item->tool()->name() << endl; enqueue(item); while(!oldqueue->isEmpty()) { KILE_DEBUG_MAIN << "\tenqueueing: " << oldqueue->head()->tool()->name() << endl; enqueue(oldqueue->dequeue()); } } } Manager::Manager(KileInfo *ki, KConfig *config, KileWidget::OutputView *output, QStackedWidget *stack, QAction *stop, uint to, KActionCollection *ac) : m_ki(ki), m_config(config), m_output(output), m_stack(stack), m_stop(stop), m_bClear(true), m_nLastResult(Success), m_nTimeout(to), m_bibliographyBackendSelectAction(Q_NULLPTR) { connect(m_ki->parserManager(), SIGNAL(documentParsingComplete()), this, SLOT(handleDocumentParsingComplete())); connect(this, SIGNAL(childToolSpawned(KileTool::Base*,KileTool::Base*)), m_ki->errorHandler(), SLOT(handleSpawnedChildTool(KileTool::Base*, KileTool::Base*))); m_timer = new QTimer(this); connect(m_timer, SIGNAL(timeout()), this, SLOT(enableClear())); connect(stop, SIGNAL(triggered()), this, SLOT(stop())); connect(stop, SIGNAL(destroyed(QObject*)), this, SLOT(stopActionDestroyed())); connect(m_ki->errorHandler(), SIGNAL(currentLaTeXOutputHandlerChanged(LaTeXOutputHandler*)), SLOT(currentLaTeXOutputHandlerChanged(LaTeXOutputHandler*))); //create actions must be invoked before buildBibliographyBackendSelection()! createActions(ac); buildBibliographyBackendSelection(); connect(m_ki->configurationManager(), SIGNAL(configChanged()), SLOT(buildBibliographyBackendSelection())); } Manager::~Manager() { KILE_DEBUG_MAIN; for(QQueue::iterator i = m_queue.begin(); i != m_queue.end(); ++i) { // this will also stop any running processes delete (*i)->tool(); delete (*i); } // tools have the tool manager as parent; so, all remaining tools will be deleted // after this, i.e. those that were scheduled for deletion via 'deleteLater' but // are no longer member of the queue } bool Manager::shouldBlock() { return m_queue.shouldBlock(); } // in some cases the pointer m_stop might not be valid, therefore this helper function comes in handy void Manager::setEnabledStopButton(bool state){ if(m_stop){ m_stop->setEnabled(state); } } void Manager::enableClear() { m_bClear = true; } bool Manager::queryContinue(const QString & question, const QString & caption /*= QString()*/) { return (KMessageBox::warningContinueCancel(m_stack, question, caption, KStandardGuiItem::cont(), KStandardGuiItem::no(), "showNotALaTeXRootDocumentWarning") == KMessageBox::Continue); } void Manager::run(Base *tool) { // if the tool requests a save-all operation, we wait for the parsing to // be finished before launching it if(!tool->requestSaveAll() || m_ki->parserManager()->isDocumentParsingComplete()) { // parsing done, we can start the tool immediately runImmediately(tool); return; } connect(tool, SIGNAL(aboutToBeDestroyed(KileTool::Base*)), this, SLOT(toolScheduledAfterParsingDestroyed(KileTool::Base*)), Qt::UniqueConnection); if(!m_toolsScheduledAfterParsingList.contains(tool)) { m_toolsScheduledAfterParsingList.push_back(tool); } } void Manager::toolScheduledAfterParsingDestroyed(KileTool::Base *tool) { m_toolsScheduledAfterParsingList.removeAll(tool); } void Manager::handleDocumentParsingComplete() { Q_FOREACH(Base *tool, m_toolsScheduledAfterParsingList) { disconnect(tool, SIGNAL(aboutToBeDestroyed(KileTool::Base*)), this, SLOT(toolScheduledAfterParsingDestroyed(KileTool::Base*))); runImmediately(tool); } m_toolsScheduledAfterParsingList.clear(); } int Manager::runImmediately(Base *tool, bool insertNext /*= false*/, bool block /*= false*/, Base *parent /*= Q_NULLPTR*/) { KILE_DEBUG_MAIN << "==KileTool::Manager::runImmediately(Base *)============" << endl; if(m_bClear && (m_queue.count() == 0)) { m_ki->errorHandler()->clearMessages(); m_output->clear(); } if(dynamic_cast(tool)) { connect(tool, SIGNAL(done(KileTool::Base*, int, bool)), m_ki->errorHandler(), SLOT(handleLaTeXToolDone(KileTool::Base*, int, bool))); } if(tool->needsToBePrepared()) { tool->prepareToRun(); } //FIXME: shouldn't restart timer if a Sequence command takes longer than the 10 secs //restart timer, so we only clear the logs if a tool is started after 10 sec. m_bClear = false; m_timer->start(m_nTimeout); if(insertNext) { m_queue.enqueueNext(new QueueItem(tool, block)); } else { m_queue.enqueue(new QueueItem(tool, block)); } if(parent) { emit(childToolSpawned(parent,tool)); } KILE_DEBUG_MAIN << "\tin queue: " << m_queue.count() << endl; if(m_queue.count() == 1) { return runNextInQueue(); } else if(m_queue.count() > 1) { return Running; } else { return ConfigureFailed; } } int Manager::runChildNext(Base *parent, Base *tool, bool block /*= false*/) { parent->setupAsChildTool(tool); return runImmediately(tool, true, block, parent); } int Manager::runNextInQueue() { Base *head = m_queue.tool(); if(head) { if (m_ki->errorHandler()->areMessagesShown()) { m_ki->errorHandler()->addEmptyLineToMessages(); } if(!head->isPrepared()) { head->prepareToRun(); } int status; if((status=head->run()) != Running) { //tool did not even start, clear queue stop(); for(QQueue::iterator i = m_queue.begin(); i != m_queue.end(); ++i) { (*i)->tool()->deleteLater(); delete (*i); } m_queue.clear(); return status; } m_ki->errorHandler()->startToolLogOutput(); emit(toolStarted()); return Running; } return ConfigureFailed; } Base* Manager::createTool(const QString& name, const QString &cfg, bool prepare) { if(!m_factory) { m_ki->errorHandler()->printMessage(Error, i18n("No factory installed, contact the author of Kile.")); return Q_NULLPTR; } Base* pTool = m_factory->create(name, cfg, prepare); if(!pTool) { m_ki->errorHandler()->printMessage(Error, i18n("Unknown tool %1.", name)); return Q_NULLPTR; } initTool(pTool); return pTool; } void Manager::initTool(Base *tool) { tool->setInfo(m_ki); tool->setConfig(m_config); connect(tool, SIGNAL(message(int, const QString &, const QString &)), m_ki->errorHandler(), SLOT(printMessage(int, const QString &, const QString &))); connect(tool, SIGNAL(output(const QString &)), m_output, SLOT(receive(const QString &))); connect(tool, SIGNAL(done(KileTool::Base*,int,bool)), this, SLOT(done(KileTool::Base*, int))); connect(tool, SIGNAL(start(KileTool::Base*)), this, SLOT(started(KileTool::Base*))); } void Manager::started(Base *tool) { KILE_DEBUG_MAIN << "STARTING tool: " << tool->name() << endl; setEnabledStopButton(true); if (tool->isViewer()) { if(tool == m_queue.tool()) { m_queue.dequeue(); } setEnabledStopButton(false); QTimer::singleShot(100, this, SLOT(runNextInQueue())); } } void Manager::stop() { setEnabledStopButton(false); if(m_queue.tool()) { m_queue.tool()->stop(); } } void Manager::stopLivePreview() { KILE_DEBUG_MAIN; Base *tool = m_queue.tool(); if(tool && tool->isPartOfLivePreview()) { setEnabledStopButton(false); tool->stop(); } deleteLivePreviewToolsFromQueue(); deleteLivePreviewToolsFromRunningAfterParsingQueue(); } void Manager::stopActionDestroyed() { m_stop = Q_NULLPTR; } void Manager::done(KileTool::Base *tool, int result) { setEnabledStopButton(false); m_nLastResult = result; m_ki->errorHandler()->endToolLogOutput(); if(tool != m_queue.tool()) { //oops, tool finished async, could happen with view tools tool->deleteLater(); return; } QueueItem *item = m_queue.dequeue(); item->tool()->deleteLater(); delete item; if(result == Aborted) { tool->sendMessage(Error, i18n("Aborted")); } if(result != Success && result != Silent) { //abort execution, delete all remaining tools if(tool->isPartOfLivePreview()) { // live preview was stopped / aborted deleteLivePreviewToolsFromQueue(); // don't forget to run non-live preview tools that are pending runNextInQueue(); } else { for(QQueue::iterator i = m_queue.begin(); i != m_queue.end(); ++i) { (*i)->tool()->deleteLater(); delete (*i); } m_queue.clear(); m_ki->focusLog(); } } else { //continue runNextInQueue(); } } void Manager::deleteLivePreviewToolsFromQueue() { for(QQueue::iterator i = m_queue.begin(); i != m_queue.end();) { QueueItem *item = *i; if(item->tool()->isPartOfLivePreview()) { i = m_queue.erase(i); item->tool()->deleteLater(); delete item; } else { ++i; } } } void Manager::deleteLivePreviewToolsFromRunningAfterParsingQueue() { for(QQueue::iterator i = m_toolsScheduledAfterParsingList.begin(); i != m_toolsScheduledAfterParsingList.end();) { Base *tool = *i; if(tool->isPartOfLivePreview()) { i = m_toolsScheduledAfterParsingList.erase(i); delete tool; } else { ++i; } } } QString Manager::currentGroup(const QString &name, bool usequeue, bool useproject) { if (useproject) { KileProject *project = m_ki->docManager()->activeProject(); if(project) { QString cfg = configName(name, dynamic_cast(project->config())); if(cfg.length() > 0) { return groupFor(name, cfg); } } } if(usequeue && !m_queue.isEmpty() && m_queue.tool() && (m_queue.tool()->name() == name) && (!m_queue.tool()->toolConfig().isEmpty())) { return groupFor(name, m_queue.tool()->toolConfig()); } else { return groupFor(name, m_config); } } bool Manager::retrieveEntryMap(const QString & name, Config & map, bool usequeue, bool useproject, const QString & cfg /*= QString()*/) { QString group = (cfg.isEmpty()) ? currentGroup(name, usequeue, useproject) : groupFor(name, cfg); KILE_DEBUG_MAIN << "==KileTool::Manager::retrieveEntryMap=============" << endl; KILE_DEBUG_MAIN << "\t" << name << " => " << group << endl; if(m_config->hasGroup(group)) { map = m_config->entryMap(group); //use project overrides KileProject *project = m_ki->docManager()->activeProject(); if(useproject && project) { KConfig *prjcfg = dynamic_cast(project->config()); if(prjcfg) { QString grp = groupFor(name, prjcfg); Config prjmap = prjcfg->entryMap(grp); for (Config::Iterator it = prjmap.begin(); it != prjmap.end(); ++it) { map[it.key()] = it.value(); } } } } else { return false; } return true; } void Manager::saveEntryMap(const QString & name, Config & map, bool usequeue, bool useproject) { KILE_DEBUG_MAIN << "==KileTool::Manager::saveEntryMap=============" << endl; QString group = currentGroup(name, usequeue, useproject); KILE_DEBUG_MAIN << "\t" << name << " => " << group << endl; KConfigGroup configGroup = m_config->group(group); Config::Iterator it; for(it = map.begin() ; it != map.end(); ++it) { if(!it.value().isEmpty()) { configGroup.writeEntry(it.key(), it.value()); } } } bool Manager::configure(Base *tool, const QString& cfg /* = QString() */) { KILE_DEBUG_MAIN << "==KileTool::Manager::configure()===============" << endl; //configure the tool Config map; if(!retrieveEntryMap(tool->name(), map, true, true, cfg)) { QString group = (cfg.isEmpty()) ? currentGroup(tool->name(), true, true) : groupFor(tool->name(), cfg); m_ki->errorHandler()->printMessage(Error, i18n("Cannot find the tool \"%1\" in the configuration database.", group)); return false; } tool->setEntryMap(map); return true; } void Manager::wantGUIState(const QString & state) { KILE_DEBUG_MAIN << "REQUESTED state: " << state << endl; emit(requestGUIState(state)); } KileView::Manager* Manager::viewManager() { return m_ki->viewManager(); } KileTool::LivePreviewManager* Manager::livePreviewManager() { return m_ki->livePreviewManager(); } KileParser::Manager* Manager::parserManager() { return m_ki->parserManager(); } QStringList toolList(KConfig *config, bool menuOnly) { KILE_DEBUG_MAIN << "==KileTool::toolList()==================" << endl; - QStringList groups = config->groupList(), tools; + const QStringList groups = config->groupList(); + QStringList tools; + QRegExp re = QRegExp("Tool/(.+)/.+"); QString name; - for(int i = 0; i < groups.count(); ++i) { - if(re.exactMatch(groups[i])) { + for(auto group : groups) { + if(!config->hasGroup(group)) { // 'group' might have been deleted + continue; // work around bug 384039 + } + if(re.exactMatch(group)) { name = configName(re.cap(1), config); - if(name.isEmpty() || !groups[i].endsWith(name)) { + if(name.isEmpty() || !group.endsWith(name)) { continue; } if((!menuOnly) || (menuFor(re.cap(1), config) != "none")) { tools.append(re.cap(1)); } } } tools.sort(); // KILE_DEBUG_MAIN << "tools " << tools.join(", "); return tools; } QList toolsWithConfigurationsBasedOnClass(KConfig *config, const QString& className) { - QStringList groups = config->groupList(), tools; + const QStringList groups = config->groupList(); + QStringList tools; + QRegExp re = QRegExp("Tool/(.+)/(.+)"); QList toReturn; - for(int i = 0; i < groups.count(); ++i) { - if(re.exactMatch(groups[i])) { + for(auto group : groups) { + if(!config->hasGroup(group)) { // 'group' might have been deleted + continue; // work around bug 384039 + } + if(re.exactMatch(group)) { const QString toolName = re.cap(1); const QString configName = re.cap(2); if(toolName.isEmpty()) { continue; } - if(config->group(groups[i]).readEntry("class", "") == className) { + if(config->group(group).readEntry("class", "") == className) { toReturn.push_back(ToolConfigPair(toolName, configName)); } } } return toReturn; } QString configName(const QString & tool, KConfig *config) { return config->group("Tools").readEntry(tool, QString()); } void Manager::setConfigName(const QString &tool, const QString &name) { KileTool::setConfigName(tool, name, m_config); } void setConfigName(const QString &tool, const QString &name, KConfig *config) { KILE_DEBUG_MAIN << "==KileTool::Manager::setConfigName(" << tool << "," << name << ")===============" << endl; config->group("Tools").writeEntry(tool, name); } QString groupFor(const QString &tool, KConfig *config) { return groupFor(tool, configName(tool, config)); } QString groupFor(const QString& tool, const QString& cfg /* = Default */ ) { QString group = "Tool/" + tool + '/' + cfg; KILE_DEBUG_MAIN << "groupFor(const QString &" << tool << ", const QString & " << cfg << " ) = " << group; return group; } void extract(const QString &str, QString &tool, QString &cfg) { static QRegExp re("([^\\(]*)\\((.*)\\)"); QString lcl = str; lcl.trimmed(); cfg.clear(); if(re.exactMatch(lcl)) { tool = re.cap(1).trimmed(); cfg = re.cap(2).trimmed(); } else tool = lcl; KILE_DEBUG_MAIN << "===void extract(const QString &str = " << str << " , QString &tool = " << tool << ", QString &cfg = " << cfg << " )===" << endl; } QString format(const QString & tool, const QString &cfg) { if (!cfg.isEmpty()) { return tool + '(' + cfg + ')'; } else { return tool; } } QStringList configNames(const QString &tool, KConfig *config) { - QStringList groups = config->groupList(), configs; + const QStringList groups = config->groupList(); + QStringList configs; + QRegExp re = QRegExp("Tool/"+ tool +"/(.+)"); - for(int i = 0; i < groups.count(); ++i) { - if(re.exactMatch(groups[i])) { + for(auto group : groups) { + if(!config->hasGroup(group)) { // 'group' might have been deleted + continue; // work around bug 384039 + } + if(re.exactMatch(group)) { configs.append(re.cap(1)); } } return configs; } QString commandFor(const QString& toolName, const QString& configName, KConfig *config) { return config->group(groupFor(toolName, configName)).readEntry("command", ""); } QString menuFor(const QString &tool, KConfig *config) { return config->group("ToolsGUI").readEntry(tool, "Other,application-x-executable").section(',', 0, 0); } QString iconFor(const QString &tool, KConfig *config) { return config->group("ToolsGUI").readEntry(tool, "Other,application-x-executable").section(',', 1, 1); } void setGUIOptions(const QString &tool, const QString &menu, const QString &icon, KConfig *config) { QString entry = menu + ',' + icon; config->group("ToolsGUI").writeEntry(tool, entry); } QString categoryFor(const QString &clss) { if(clss == "Compile" || clss == "LaTeX") { return "Compile"; } if(clss == "Convert") { return "Convert"; } if(clss == "View" || clss == "ViewBib" || clss == "ViewHTML" || clss == "ForwardDVI") { return "View"; } if(clss == "Sequence") { return "Sequence"; } if(clss == "Archive") { return "Archive"; } return "Base"; } } bool KileTool::Manager::containsBibliographyTool(const ToolConfigPair& p) const { return m_bibliographyToolsList.contains(p); } KileTool::ToolConfigPair KileTool::Manager::findFirstBibliographyToolForCommand(const QString& command) const { // for now we will just select the first suitable tool Q_FOREACH(const KileTool::ToolConfigPair& tool, m_bibliographyToolsList) { const QString toolCommand = commandFor(tool, m_config); if (QString::compare(command, toolCommand, Qt::CaseInsensitive) == 0) { return tool; } } return KileTool::ToolConfigPair(); } void KileTool::Manager::buildBibliographyBackendSelection() { m_bibliographyBackendSelectAction->removeAllActions(); m_bibliographyBackendSelectAction->menu()->clear(); for(QMap::iterator i = m_bibliographyBackendActionMap.begin(); i != m_bibliographyBackendActionMap.end(); ++i) { delete i.value(); } m_bibliographyBackendActionMap.clear(); m_bibliographyToolsList.clear(); m_bibliographyBackendSelectAction->addAction(m_bibliographyBackendAutodetectAction); m_bibliographyToolsList = toolsWithConfigurationsBasedOnClass(m_config, BibliographyCompile::ToolClass); std::sort(m_bibliographyToolsList.begin(), m_bibliographyToolsList.end()); // necessary for the user-visible actions in the menu bar Q_FOREACH(const ToolConfigPair& tool, m_bibliographyToolsList) { // create an action for backend selection QAction * action = m_bibliographyBackendSelectAction->addAction(tool.userStringRepresentation()); action->setData(qVariantFromValue(tool)); m_bibliographyBackendActionMap[tool] = action; } m_bibliographyBackendSelectAction->menu()->addSeparator(); m_bibliographyBackendSelectAction->menu()->addAction(m_bibliographyBackendResetAutodetectedAction); currentLaTeXOutputHandlerChanged(m_ki->findCurrentLaTeXOutputHandler()); } void KileTool::Manager::createActions(KActionCollection *ac) { delete m_bibliographyBackendSelectAction; m_bibliographyBackendSelectAction = new KSelectAction(i18n("Bibliography Back End"), this); m_bibliographyBackendAutodetectAction = m_bibliographyBackendSelectAction->addAction(i18n("Auto-Detect")); m_bibliographyBackendAutodetectAction->setStatusTip(i18n("Auto-detect the bibliography back end from LaTeX output")); m_bibliographyBackendSelectAction->setChecked(false); ac->addAction("bibbackend_select", m_bibliographyBackendSelectAction); m_bibliographyBackendResetAutodetectedAction = new QAction(i18n("Reset Auto-Detected Back End"), this); m_bibliographyBackendResetAutodetectedAction->setEnabled(false); connect(m_bibliographyBackendSelectAction, SIGNAL(triggered(QAction*)), SLOT(bibliographyBackendSelectedByUser())); connect(m_bibliographyBackendResetAutodetectedAction, SIGNAL(triggered(bool)), SLOT(resetAutodetectedBibliographyBackend())); connect(m_bibliographyBackendAutodetectAction, SIGNAL(toggled(bool)), m_bibliographyBackendResetAutodetectedAction, SLOT(setEnabled(bool))); } void KileTool::Manager::bibliographyBackendSelectedByUser() { LaTeXOutputHandler* h = m_ki->findCurrentLaTeXOutputHandler(); QAction* currentBackendAction = m_bibliographyBackendSelectAction->currentAction(); if (currentBackendAction == m_bibliographyBackendAutodetectAction) { h->setBibliographyBackendToolUserOverride(ToolConfigPair()); } else { //here we do not need to check existence of tool h->setBibliographyBackendToolUserOverride(currentBackendAction->data().value()); h->setBibliographyBackendToolAutoDetected(ToolConfigPair()); } } void KileTool::Manager::currentLaTeXOutputHandlerChanged(LaTeXOutputHandler* handler) { if(!handler) { m_bibliographyBackendSelectAction->setEnabled(false); return; } m_bibliographyBackendSelectAction->setEnabled(true); if (!m_bibliographyBackendActionMap.empty()) { ToolConfigPair userOverrideBibBackend = handler->bibliographyBackendToolUserOverride(); if(!userOverrideBibBackend.isValid()) { m_bibliographyBackendAutodetectAction->setChecked(true); } else { // here we have to check whether the action exists QMap::const_iterator i = m_bibliographyBackendActionMap.constFind(userOverrideBibBackend); if (i != m_bibliographyBackendActionMap.constEnd()) { i.value()->setChecked(true); } else { // the user previously selected a bibtool backend which is (no longer) present - let's use autodetection; // this is done analogously in 'LaTeX::determineBibliographyBackend' m_bibliographyBackendAutodetectAction->setChecked(true); } } } else { m_bibliographyBackendAutodetectAction->setChecked(true); } } void KileTool::Manager::resetAutodetectedBibliographyBackend() { LaTeXOutputHandler* h = m_ki->findCurrentLaTeXOutputHandler(); if (h) { h->setBibliographyBackendToolAutoDetected(ToolConfigPair()); } }