You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kile/src/kile/kileproject.cpp

815 lines
21 KiB

/***************************************************************************
begin : Fri Aug 1 2003
copyright : (C) 2003 by Jeroen Wijnhout
: (C) 2007 by Holger Danielsson
email : Jeroen.Wijnhout@kdemail.net
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
// - allowed extensions are always defined as list, f.e.: .tex .ltx .latex
#include "kileproject.h"
#include "kileversion.h"
#include <tqstringlist.h>
#include <tqfileinfo.h>
#include <tqdir.h>
#include <ksimpleconfig.h>
#include <tdelocale.h>
#include <tdeglobal.h>
#include "kiledebug.h"
#include <tdemessagebox.h>
#include "kiledocumentinfo.h"
#include "kiledocmanager.h"
#include "kiletoolmanager.h"
#include "kileinfo.h"
#include "kileextensions.h"
#include <krun.h>
/*
01/24/06 tbraun
Added the logic to get versioned kilepr files
We also warn if the user wants to open a project file with a different kileprversion
*/
/*
* KileProjectItem
*/
KileProjectItem::KileProjectItem(KileProject *project, const KURL & url, int type) :
m_project(project),
m_url(url),
m_type(type),
m_docinfo(0L),
m_parent(0L),
m_child(0L),
m_sibling(0L),
m_nLine(0),
m_order(-1)
{
m_highlight=m_encoding=TQString();
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::print(int level)
{
TQString str;
str.fill('\t', level);
KILE_DEBUG() << str << "+" << url().fileName() << endl;
if (firstChild())
firstChild()->print(++level);
if (sibling())
sibling()->print(level);
}
void KileProjectItem::allChildren(TQPtrList<KileProjectItem> *list) const
{
KileProjectItem *item = firstChild();
// KILE_DEBUG() << "\tKileProjectItem::allChildren(" << list->count() << ")" << endl;
while(item != 0)
{
list->append(item);
// KILE_DEBUG() << "\t\tappending " << item->url().fileName() << endl;
item->allChildren(list);
item = item->sibling();
}
}
void KileProjectItem::setInfo(KileDocument::TextInfo *docinfo)
{
m_docinfo = docinfo;
if(docinfo)
{
connect(docinfo,TQT_SIGNAL(urlChanged(KileDocument::Info*, const KURL &)), this, TQT_SLOT(slotChangeURL(KileDocument::Info*, const KURL &)));
connect(docinfo,TQT_SIGNAL(depChanged()), m_project, TQT_SLOT(buildProjectTree()));
}
}
void KileProjectItem::changeURL(const KURL &url)
{
// don't allow empty URLs
if(!url.isEmpty() && m_url != url)
{
m_url = url;
emit(urlChanged(this));
}
}
void KileProjectItem::slotChangeURL(KileDocument::Info*, const KURL &url)
{
changeURL(url);
}
/*
* KileProject
*/
KileProject::KileProject(const TQString& name, const KURL& url, KileDocument::Extensions *extensions) : TQObject(0,name.ascii()), m_invalid(false), m_masterDocument(TQString()), m_useMakeIndexOptions(false)
{
init(name, url, extensions);
}
KileProject::KileProject(const KURL& url, KileDocument::Extensions *extensions) : TQObject(0,url.fileName().ascii()), m_invalid(false), m_masterDocument(TQString()), m_useMakeIndexOptions(false)
{
init(url.fileName(), url, extensions);
}
KileProject::~KileProject()
{
KILE_DEBUG() << "DELETING KILEPROJECT " << m_projecturl.url() << endl;
delete m_config;
}
void KileProject::init(const TQString& name, const KURL& url, KileDocument::Extensions *extensions)
{
m_name = name;
m_projecturl = KileDocument::Manager::symlinkFreeURL( url);;
m_projectitems.setAutoDelete(true);
m_config = new KSimpleConfig(m_projecturl.path());
m_extmanager = extensions;
m_baseurl = m_projecturl.directory();
m_baseurl.cleanPath(true);
KILE_DEBUG() << "KileProject m_baseurl = " << m_baseurl.path() << endl;
if (TQFileInfo(url.path()).exists())
{
load();
}
else
{
//create the project file
m_config->setGroup("General");
m_config->writeEntry("name", m_name);
m_config->writeEntry("kileprversion", kilePrVersion);
m_config->writeEntry("kileversion", kileVersion);
m_config->sync();
}
}
void KileProject::setLastDocument(const KURL &url)
{
if ( item(url) != 0 )
m_lastDocument = KileDocument::Manager::symlinkFreeURL(url);
}
void KileProject::setExtensions(KileProjectItem::Type type, const TQString & ext)
{
if (type<KileProjectItem::Source || type>KileProjectItem::Image)
{
kdWarning() << "ERROR: TYPE<1 or TYPE>3" << endl;
return;
}
// first we take all standard extensions
TQStringList standardExtList;
if ( type == KileProjectItem::Source )
standardExtList = TQStringList::split(" ", m_extmanager->latexDocuments() );
else if ( type == KileProjectItem::Package )
standardExtList = TQStringList::split(" ", m_extmanager->latexPackages() );
else // if ( type == KileProjectItem::Image )
standardExtList = TQStringList::split(" ", m_extmanager->images() );
// now we scan user defined list and accept all extension,
// except standard extensions of course
TQString userExt;
if ( ! ext.isEmpty() )
{
TQStringList userExtList;
TQStringList::ConstIterator it;
TQStringList list = TQStringList::split(" ", ext);
for ( it=list.begin(); it != list.end(); ++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);
}
}
}
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)
TQString 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::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].search(item->url().fileName()) != -1)
{
item->setType(i);
unknown = false;
break;
}
}
if (unknown)
item->setType(KileProjectItem::Other);
}
void KileProject::readMakeIndexOptions()
{
TQString grp = KileTool::groupFor("MakeIndex", m_config);
//get the default value
TDEConfig *cfg = TDEGlobal::config();
cfg->setGroup(KileTool::groupFor("MakeIndex", KileTool::configName("MakeIndex", cfg)));
TQString deflt = cfg->readEntry("options", "'%S'.idx");
if ( useMakeIndexOptions() && !grp.isEmpty() )
{
m_config->setGroup(grp);
TQString val = m_config->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);
}
TQString KileProject::addBaseURL(const TQString &path)
{
KILE_DEBUG() << "===addBaseURL(const TQString & " << path << " )" << endl;
if ( path.isEmpty())
return path;
else if ( path.startsWith("/") )
return KileDocument::Manager::symlinkFreeURL(KURL::fromPathOrURL(path)).path();
else
return KileDocument::Manager::symlinkFreeURL(KURL::fromPathOrURL(m_baseurl.path() + '/' +path)).path();
}
TQString KileProject::removeBaseURL(const TQString &path)
{
if ( path.startsWith("/") )
{
TQFileInfo info(path);
TQString relPath = findRelativePath(path);
KILE_DEBUG() << "removeBaseURL path is" << path << " , relPath is " << relPath << endl;
return relPath;
}
else
{
return path;
}
}
bool KileProject::load()
{
KILE_DEBUG() << "KileProject: loading..." <<endl;
//load general settings/options
m_config->setGroup("General");
m_name = m_config->readEntry("name", i18n("Project"));
m_kileversion = m_config->readEntry("kileversion",TQString());
m_kileprversion = m_config->readEntry("kileprversion",TQString());
if(!m_kileprversion.isNull() && m_kileprversion.toInt() > kilePrVersion.toInt())
{
if(KMessageBox::warningYesNo(0L,i18n("The project file of %1 was created by a newer version of kile.\
Opening it can lead to unexpected results.\n\
Do you really want to continue (not recommended)?").arg(m_name),
TQString(), KStdGuiItem::yes(), KStdGuiItem::no(),TQString(),KMessageBox::Dangerous) == KMessageBox::No)
{
m_invalid=true;
return false;
}
}
TQString master = addBaseURL(m_config->readEntry("masterDocument", TQString()));
KILE_DEBUG() << "masterDoc == " << master << endl;
setMasterDocument(master);
setExtensions(KileProjectItem::Source, m_config->readEntry("src_extensions",m_extmanager->latexDocuments()));
setExtensions(KileProjectItem::Package, m_config->readEntry("pkg_extensions",m_extmanager->latexPackages()));
setExtensions(KileProjectItem::Image, m_config->readEntry("img_extensions",m_extmanager->images()));
setQuickBuildConfig(KileTool::configName("QuickBuild", m_config));
if( KileTool::configName("MakeIndex",m_config).compare("Default") == 0)
setUseMakeIndexOptions(true);
else
setUseMakeIndexOptions(false);
readMakeIndexOptions();
KURL url;
KileProjectItem *item;
TQStringList groups = m_config->groupList();
//retrieve all the project files and create and initialize project items for them
for (uint i=0; i < groups.count(); ++i)
{
if (groups[i].left(5) == "item:")
{
TQString path = groups[i].mid(5);
if (path[0] == '/' )
{
url = KURL::fromPathOrURL(path);
}
else
{
url = m_baseurl;
url.addPath(path);
url.cleanPath(true);
}
item = new KileProjectItem(this, KileDocument::Manager::symlinkFreeURL(url));
setType(item);
m_config->setGroup(groups[i]);
item->setOpenState(m_config->readBoolEntry("open", true));
item->setEncoding(m_config->readEntry("encoding", TQString()));
item->setHighlight(m_config->readEntry("highlight",TQString()));
item->setArchive(m_config->readBoolEntry("archive", true));
item->setLineNumber(m_config->readNumEntry("line", 0));
item->setColumnNumber(m_config->readNumEntry("column", 0));
item->setOrder(m_config->readNumEntry("order", -1));
item->changePath(groups[i].mid(5));
connect(item, TQT_SIGNAL(urlChanged(KileProjectItem*)), this, TQT_SLOT(itemRenamed(KileProjectItem*)) );
}
}
// only call this after all items are created, otherwise setLastDocument doesn't accept the url
m_config->setGroup("General");
setLastDocument(KURL::fromPathOrURL(addBaseURL(m_config->readEntry("lastDocument", TQString()))));
// dump();
return true;
}
bool KileProject::save()
{
KILE_DEBUG() << "KileProject: saving..." <<endl;
m_config->setGroup("General");
m_config->writeEntry("name", m_name);
m_config->writeEntry("kileprversion", kilePrVersion);
m_config->writeEntry("kileversion", kileVersion);
KILE_DEBUG() << "KileProject::save() masterDoc = " << removeBaseURL(m_masterDocument) << endl;
m_config->writeEntry("masterDocument", removeBaseURL(m_masterDocument));
m_config->writeEntry("lastDocument", removeBaseURL(m_lastDocument.path()));
writeConfigEntry("src_extensions",m_extmanager->latexDocuments(),KileProjectItem::Source);
writeConfigEntry("pkg_extensions",m_extmanager->latexPackages(),KileProjectItem::Package);
writeConfigEntry("img_extensions",m_extmanager->images(),KileProjectItem::Image);
// only to avoid problems with older versions
m_config->writeEntry("src_extIsRegExp", false);
m_config->writeEntry("pkg_extIsRegExp", false);
m_config->writeEntry("img_extIsRegExp", false);
KileProjectItem *item;
for (uint i=0; i < m_projectitems.count(); ++i)
{
item = m_projectitems.at(i);
m_config->setGroup("item:"+item->path());
m_config->writeEntry("open", item->isOpen());
m_config->writeEntry("encoding", item->encoding());
m_config->writeEntry("highlight", item->highlight());
m_config->writeEntry("archive", item->archive());
m_config->writeEntry("line", item->lineNumber());
m_config->writeEntry("column", item->columnNumber());
m_config->writeEntry("order", item->order());
}
KileTool::setConfigName("QuickBuild", quickBuildConfig(), m_config);
writeUseMakeIndexOptions();
if ( useMakeIndexOptions() )
{
TQString grp = KileTool::groupFor("MakeIndex", m_config);
if ( grp.isEmpty() ) grp = "Default";
m_config->setGroup(grp);
m_config->writeEntry("options", makeIndexOptions() );
}
KILE_DEBUG() << "Check if the config file is writeable: " << m_config->checkConfigFilesWritable(false) << endl;
m_config->sync();
// dump();
return true;
}
void KileProject::writeConfigEntry(const TQString &key, const TQString &standardExt, KileProjectItem::Type type)
{
TQString userExt = extensions(type);
if ( userExt.isEmpty() )
m_config->writeEntry(key,standardExt);
else
m_config->writeEntry(key,standardExt + ' ' + extensions(type));
}
void KileProject::buildProjectTree()
{
KILE_DEBUG() << "==KileProject::buildProjectTree==========================" << endl;
//determine the parent doc for each item (TODO:an item can only have one parent, not necessarily true for LaTeX docs)
const TQStringList *deps;
TQString dep;
KileProjectItem *itm;
KURL url;
TQPtrListIterator<KileProjectItem> it(m_projectitems);
//clean first
while (it.current())
{
(*it)->setParent(0);
++it;
}
//use the dependencies list of the documentinfo object to determine the parent
it.toFirst();
while (it.current())
{
//set the type correctly (changing m_extensions causes a call to buildProjectTree)
setType(*it);
if ( (*it)->getInfo() )
{
deps = (*it)->getInfo()->dependencies();
for (uint i=0; i < deps->count(); ++i)
{
dep = (*deps)[i];
if( m_extmanager->isTexFile(dep) )
url = KileInfo::checkOtherPaths(m_baseurl,dep,KileInfo::texinputs);
else if( m_extmanager->isBibFile(dep) )
url = KileInfo::checkOtherPaths(m_baseurl,dep,KileInfo::bibinputs);
itm = item(url);
if (itm && (itm->parent() == 0))
itm->setParent(*it);
}
}
++it;
}
//make a list of all the root items (items with parent == 0)
m_rootItems.clear();
it.toFirst();
while (it.current())
{
if ((*it)->parent() == 0) m_rootItems.append(*it);
++it;
}
emit(projectTreeChanged(this));
}
KileProjectItem* KileProject::item(const KURL & url)
{
TQPtrListIterator<KileProjectItem> it(m_projectitems);
while (it.current())
{
if ((*it)->url() == url)
return *it;
++it;
}
return 0;
}
KileProjectItem* KileProject::item(const KileDocument::Info *info)
{
TQPtrListIterator<KileProjectItem> it(m_projectitems);
KileProjectItem *current;
while ((current = it.current()) != 0)
{
++it;
if (current->getInfo() == info)
{
return current;
}
}
return 0;
}
void KileProject::add(KileProjectItem* item)
{
KILE_DEBUG() << "KileProject::add projectitem" << item->url().path() << endl;
setType(item);
item->changePath(findRelativePath(item->url()));
connect(item, TQT_SIGNAL(urlChanged(KileProjectItem*)), this, TQT_SLOT(itemRenamed(KileProjectItem*)) );
m_projectitems.append(item);
// dump();
}
void KileProject::remove(const KileProjectItem* item)
{
if (m_config->hasGroup("item:"+item->path()))
m_config->deleteGroup("item:"+item->path());
else
kdWarning() << "KileProject::remove() Failed to delete the group corresponding to this item!!!" <<endl;
KILE_DEBUG() << "KileProject::remove" << endl;
m_projectitems.remove(item);
// dump();
}
void KileProject::itemRenamed(KileProjectItem *item)
{
KILE_DEBUG() << "==KileProject::itemRenamed==========================" << endl;
KILE_DEBUG() << "\t" << item->url().fileName() << endl;
m_config->deleteGroup("item:"+item->path());
//config.sync();
item->changePath(findRelativePath(item->url()));
}
TQString KileProject::findRelativePath(const KURL &url)
{
TQString basepath = m_baseurl.path();
TQString path = url.directory();
TQString filename = url.fileName();
KILE_DEBUG() <<"===findRelativeURL==================" << endl;
KILE_DEBUG() << "\tbasepath : " << basepath << " path: " << path << endl;
// if ( basepath == path )
// {
// return "./";
// }
TQStringList basedirs = TQStringList::split("/", basepath, false);
TQStringList dirs = TQStringList::split("/", path, false);
uint nDirs = dirs.count();
//uint nBaseDirs = basedirs.count();
// for (uint i=0; i < basedirs.count(); ++i)
// {
// KILE_DEBUG() << "\t\tbasedirs " << i << ": " << basedirs[i] << endl;
// }
// for (uint i=0; i < dirs.count(); ++i)
// {
// KILE_DEBUG() << "\t\tdirs " << i << ": " << dirs[i] << endl;
// }
while ( dirs.count() > 0 && basedirs.count() > 0 && dirs[0] == basedirs[0] )
{
dirs.pop_front();
basedirs.pop_front();
}
// KILE_DEBUG() << "\tafter" << endl;
// for (uint i=0; i < basedirs.count(); ++i)
// {
// KILE_DEBUG() << "\t\tbasedirs " << i << ": " << basedirs[i] << endl;
// }
//
// for (uint i=0; i < dirs.count(); ++i)
// {
// KILE_DEBUG() << "\t\tdirs " << i << ": " << dirs[i] << endl;
// }
if (nDirs != dirs.count() )
{
path = dirs.join("/");
if (basedirs.count() > 0)
{
for (uint j=0; j < basedirs.count(); ++j)
{
path = "../" + path;
}
}
if ( path.length() > 0 && path.right(1) != "/" ) path = path + '/';
path = path+filename;
}
else //assume an absolute path was requested
{
path = url.path();
}
// KILE_DEBUG() << "\tpath : " << path << endl;
return path;
}
bool KileProject::contains(const KURL &url)
{
for (uint i=0; i < m_projectitems.count(); ++i)
{
if ( m_projectitems.at(i)->url() == url )
return true;
}
return false;
}
bool KileProject::contains(const KileDocument::Info *info)
{
TQPtrListIterator<KileProjectItem> it(m_projectitems);
KileProjectItem *current;
while( (current = it.current()) != 0)
{
++it;
if(current->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() != 0)
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
TQPtrListIterator<KileProjectItem> it(m_rootItems);
while ( it.current() )
{
if ( it.current()->getInfo() && it.current()->getInfo()->isLaTeXRoot() )
return it.current();
++it;
}
}
//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() << "KileProject::dump() " << m_name << endl;
for ( uint i=0; i < m_projectitems.count(); ++i)
{
KileProjectItem *item;
item = m_projectitems.at(i);
KILE_DEBUG() << "item " << i << " has path: " << item->path() << endl;
KILE_DEBUG() << "item->type() " << item->type() << endl;
KILE_DEBUG() << "OpenState: " << item->isOpen() << endl;
}
}
TQString KileProject::archiveFileList() const
{
KILE_DEBUG() << "KileProject::archiveFileList()" << endl;
TQString path,list;
TQPtrListIterator<KileProjectItem> it(m_projectitems);
while (it.current())
{
if ((*it)->archive())
{
path = (*it)->path();
KRun::shellQuote(path);
list.append(path + ' ');
}
++it;
}
return list;
}
void KileProject::setMasterDocument(const TQString & master){
if(!master.isEmpty()){
TQFileInfo fi(master);
if(fi.exists())
m_masterDocument = master;
else{
m_masterDocument = TQString();
KILE_DEBUG() << "setMasterDocument: masterDoc=NULL" << endl;
}
}
else
m_masterDocument = TQString();
emit (masterDocumentChanged(m_masterDocument));
}
#include "kileproject.moc"