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/kileprojectview.cpp

692 lines
19 KiB

/***************************************************************************
begin : Tue Aug 12 2003
copyright : (C) 2003 by Jeroen Wijnhout
(C) 2006 by Michel Ludwig
email : Jeroen.Wijnhout@kdemail.net
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 "kileprojectview.h"
#include <tqheader.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kiconloader.h>
#include <tdepopupmenu.h>
#include <kurl.h>
#include <krun.h>
#include <kmimetype.h>
#include <kurldrag.h>
#include "kileinfo.h"
#include "kiledocumentinfo.h"
#include "kiledocmanager.h"
const int KPV_ID_OPEN = 0, KPV_ID_SAVE = 1, KPV_ID_CLOSE = 2,
KPV_ID_OPTIONS = 3, KPV_ID_ADD = 4, KPV_ID_REMOVE = 5,
KPV_ID_BUILDTREE = 6, KPV_ID_ARCHIVE = 7, KPV_ID_ADDFILES = 8,
KPV_ID_INCLUDE = 9, KPV_ID_OPENWITH = 10, KPV_ID_OPENALLFILES = 11;
/*
* KileProjectViewItem
*/
void KileProjectViewItem::urlChanged(const KURL &url)
{
// don't allow empty URLs
if(!url.isEmpty())
{
setURL(url);
setText(0, url.fileName());
}
}
void KileProjectViewItem::nameChanged(const TQString & name)
{
setText(0,name);
}
void KileProjectViewItem::isrootChanged(bool isroot)
{
KILE_DEBUG() << "TQ_SLOT isrootChanged " << text(0) << " to " << isroot << endl;
if (isroot)
{
setPixmap(0,SmallIcon("masteritem"));
}
else
{
if ( text(0).right(7) == ".kilepr" )
setPixmap(0,SmallIcon("kile"));
else if (type() == KileType::ProjectItem)
setPixmap(0,SmallIcon("projectitem"));
else
setPixmap(0,SmallIcon("file"));
}
}
void KileProjectViewItem::slotURLChanged(KileDocument::Info*, const KURL & url)
{
urlChanged(url);
}
int KileProjectViewItem::compare(TQListViewItem * i, int col, bool ascending) const
{
KileProjectViewItem *item = dynamic_cast<KileProjectViewItem*>(i);
// sort:
// - first: container items in fixed order (projectfile, packages, images, other)
// - second: root items without container (sorted in ascending order)
if ( item->type() == KileType::Folder )
{
if ( type() != KileType::Folder )
return 1;
else
return ( m_folder < item->folder() ) ? -1 : 1;
}
else if ( type() == KileType::Folder )
return -1;
else
return TQListViewItem::compare(i, col, ascending);
}
/*
* KileProjectView
*/
KileProjectView::KileProjectView(TQWidget *parent, KileInfo *ki) : TDEListView(parent), m_ki(ki), m_nProjects(0), m_toggle(0)
{
addColumn(i18n("Files & Projects"),-1);
addColumn(i18n("Include in Archive"),10);
setSorting(-1);
setFocusPolicy(TQWidget::ClickFocus);
header()->hide();
setRootIsDecorated(true);
setAllColumnsShowFocus(true);
setFullWidth(true);
setSelectionModeExt(TDEListView::NoSelection);
m_popup = new TDEPopupMenu(this, "projectview_popup");
connect(this, TQ_SIGNAL(contextMenu(TDEListView *, TQListViewItem *, const TQPoint & )), this,TQ_SLOT(popup(TDEListView *, TQListViewItem * , const TQPoint & )));
connect(this, TQ_SIGNAL(executed(TQListViewItem*)), this, TQ_SLOT(slotClicked(TQListViewItem*)));
setAcceptDrops(true);
connect(this, TQ_SIGNAL(dropped(TQDropEvent *, TQListViewItem *)), m_ki->docManager(), TQ_SLOT(openDroppedURLs(TQDropEvent *)));
}
void KileProjectView::slotClicked(TQListViewItem *item)
{
if (item == 0)
item = currentItem();
KileProjectViewItem *itm = static_cast<KileProjectViewItem*>(item);
if (itm)
{
if (itm->type() == KileType::File )
emit(fileSelected(itm->url()));
else if ( itm->type() == KileType::ProjectItem )
emit(fileSelected(itm->projectItem()));
else if ( itm->type() != KileType::Folder )
{
// don't open project configuration files (*.kilepr)
if ( itm->url().path().right(7) != ".kilepr" )
{
//determine mimeType and open file with preferred application
KMimeType::Ptr pMime = KMimeType::findByURL(itm->url());
if ( pMime->name().startsWith("text/") )
emit(fileSelected(itm->url()));
else
KRun::runURL(itm->url(), pMime->name());
}
}
clearSelection();
}
}
void KileProjectView::slotFile(int id)
{
KileProjectViewItem *item = static_cast<KileProjectViewItem*>(currentItem());
if (item )
{
if ( item->type() == KileType::File )
{
switch (id)
{
case KPV_ID_OPEN : emit(fileSelected(item->url())); break;
case KPV_ID_SAVE : emit(saveURL(item->url())); break;
case KPV_ID_ADD : emit(addToProject(item->url())); break;
case KPV_ID_CLOSE : emit(closeURL(item->url())); return; //don't access "item" later on
default : break;
}
}
}
}
void KileProjectView::slotProjectItem(int id)
{
KileProjectViewItem *item = static_cast<KileProjectViewItem*>(currentItem());
if ( item )
{
if ( item->type()==KileType::ProjectItem || item->type()==KileType::ProjectExtra )
{
switch (id)
{
case KPV_ID_OPEN : emit(fileSelected(item->projectItem())); break;
case KPV_ID_SAVE : emit(saveURL(item->url())); break;
case KPV_ID_REMOVE :
emit(removeFromProject(item->projectItem()));
break;
case KPV_ID_INCLUDE :
if (item->text(1) == "*") item->setText(1,"");
else item->setText(1,"*");
emit(toggleArchive(item->projectItem()));
break;
case KPV_ID_CLOSE : emit(closeURL(item->url())); break; //we can access "item" later as it isn't deleted
case KPV_ID_OPENWITH :
KRun::displayOpenWithDialog(item->url());
break;
default : break;
}
}
}
}
void KileProjectView::slotProject(int id)
{
KileProjectViewItem *item = static_cast<KileProjectViewItem*>(currentItem());
if ( item )
{
if ( item->type() == KileType::Project )
{
switch (id)
{
case KPV_ID_BUILDTREE : emit(buildProjectTree(item->url())); break;
case KPV_ID_OPTIONS : emit(projectOptions(item->url())); break;
case KPV_ID_CLOSE : emit(closeProject(item->url())); return; //don't access "item" later on
case KPV_ID_ARCHIVE : emit(projectArchive(item->url())); break;
case KPV_ID_ADDFILES : emit(addFiles(item->url())); break;
case KPV_ID_OPENALLFILES : emit(openAllFiles(item->url())); break;
default : break;
}
}
}
}
void KileProjectView::slotRun(int id)
{
KileProjectViewItem *itm = static_cast<KileProjectViewItem*>(currentItem());
if (id == 0)
KRun::displayOpenWithDialog(itm->url());
else
KRun::run(*m_offerList[id-1], itm->url());
itm->setSelected(false);
}
//FIXME clean this mess up
void KileProjectView::popup(TDEListView *, TQListViewItem * item, const TQPoint & point)
{
if (item != 0)
{
KileProjectViewItem *itm = static_cast<KileProjectViewItem*>(item);
if ( itm->type() == KileType::Folder )
return;
m_popup->clear();
m_popup->disconnect();
bool isKilePrFile = false;
if (itm->type() != KileType::Project && itm->projectItem() && itm->projectItem()->project())
isKilePrFile = itm->projectItem()->project()->url() == itm->url();
bool insertsep = false;
if (itm->type() == KileType::ProjectExtra)
{
if ( ! isKilePrFile )
{
TDEPopupMenu *apps = new TDEPopupMenu( m_popup);
m_offerList = TDETrader::self()->query(KMimeType::findByURL(itm->url())->name(), "Type == 'Application'");
for (uint i=0; i < m_offerList.count(); ++i)
apps->insertItem(SmallIcon(m_offerList[i]->icon()), m_offerList[i]->name(), i+1);
apps->insertSeparator();
apps->insertItem(i18n("Other..."), 0);
connect(apps, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotRun(int)));
m_popup->insertItem(SmallIcon("fork"), i18n("&Open With"),apps);
insertsep = true;
}
}
if (itm->type() == KileType::File || itm->type() == KileType::ProjectItem)
{
if ( ! m_ki->isOpen(itm->url()) )
m_popup->insertItem(SmallIcon("document-open"), i18n("&Open"), KPV_ID_OPEN);
else
m_popup->insertItem(SmallIcon("document-save"), i18n("&Save"), KPV_ID_SAVE);
insertsep = true;
}
if (itm->type() == KileType::File)
{
if ( m_nProjects > 0)
{
if ( insertsep )
m_popup->insertSeparator();
m_popup->insertItem(SmallIcon("project_add"),i18n("&Add to Project"), KPV_ID_ADD);
insertsep = true;
}
connect(m_popup, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotFile(int)));
}
else if (itm->type() == KileType::ProjectItem || itm->type() == KileType::ProjectExtra)
{
KileProjectItem *pi = itm->projectItem();
if (pi)
{
if ( insertsep )
m_popup->insertSeparator();
m_popup->insertItem(i18n("&Include in Archive"), KPV_ID_INCLUDE);
m_popup->setItemChecked(KPV_ID_INCLUDE, pi->archive());
insertsep = true;
}
if ( !isKilePrFile )
{
if ( insertsep )
m_popup->insertSeparator();
m_popup->insertItem(SmallIcon("project_remove"),i18n("&Remove From Project"), KPV_ID_REMOVE);
insertsep = true;
}
connect(m_popup, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotProjectItem(int)));
}
else if (itm->type() == KileType::Project)
{
if ( insertsep )
m_popup->insertSeparator();
m_popup->insertItem(i18n("A&dd Files..."), KPV_ID_ADDFILES);
m_popup->insertSeparator();
m_popup->insertItem(i18n("Open All &Project Files"), KPV_ID_OPENALLFILES);
m_popup->insertSeparator();
m_popup->insertItem(SmallIcon("relation"),i18n("Refresh Project &Tree"), KPV_ID_BUILDTREE);
m_popup->insertItem(SmallIcon("configure"),i18n("Project &Options"), KPV_ID_OPTIONS);
m_popup->insertItem(SmallIcon("package"),i18n("&Archive"), KPV_ID_ARCHIVE);
connect(m_popup, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotProject(int)));
insertsep = true;
}
if ( (itm->type() == KileType::File) || (itm->type() == KileType::ProjectItem) || (itm->type()== KileType::Project))
{
if ( insertsep )
m_popup->insertSeparator();
m_popup->insertItem(SmallIcon("window-close"), i18n("&Close"), KPV_ID_CLOSE);
}
m_popup->exec(point);
}
}
void KileProjectView::makeTheConnection(KileProjectViewItem *item)
{
KILE_DEBUG() << "\tmakeTheConnection " << item->text(0) << endl;
if (item->type() == KileType::Project)
{
KileProject *project = m_ki->docManager()->projectFor(item->url());
if (project==0)
kdWarning() << "makeTheConnection COULD NOT FIND AN PROJECT OBJECT FOR " << item->url().path() << endl;
else
connect(project, TQ_SIGNAL(nameChanged(const TQString &)), item, TQ_SLOT(nameChanged(const TQString &)));
}
else
{
KileDocument::TextInfo *docinfo = m_ki->docManager()->textInfoFor(item->url().path());
item->setInfo(docinfo);
if (docinfo ==0 ) {KILE_DEBUG() << "\tmakeTheConnection COULD NOT FIND A DOCINFO" << endl; return;}
connect(docinfo, TQ_SIGNAL(urlChanged(KileDocument::Info*, const KURL&)), item, TQ_SLOT(slotURLChanged(KileDocument::Info*, const KURL&)));
connect(docinfo, TQ_SIGNAL(isrootChanged(bool)), item, TQ_SLOT(isrootChanged(bool)));
//set the pixmap
item->isrootChanged(docinfo->isLaTeXRoot());
}
}
KileProjectViewItem* KileProjectView::folder(const KileProjectItem *pi, KileProjectViewItem *item)
{
KileProjectViewItem *parent = parentFor(pi, item);
if (parent == 0)
{
kdError() << "no parent for " << pi->url().path() << endl;
return 0;
}
// we have already found the parent folder
if ( parent->type() == KileType::Folder )
return parent;
// we are looking at the children, if there is an existing folder for this type
KileProjectViewItem *folder;
// determine the foldername for this type
TQString foldername;
switch ( pi->type() )
{
case (KileProjectItem::ProjectFile):
foldername = i18n("projectfile");
break;
case (KileProjectItem::Package):
foldername = i18n("packages");
break;
case (KileProjectItem::Image):
foldername = i18n("images");
break;
case (KileProjectItem::Other):
default :
foldername = i18n("other");
break;
}
// if there already a folder for this type on this level?
bool found = false;
folder = parent->firstChild();
while ( folder )
{
if ( folder->text(0) == foldername )
{
found = true;
break;
}
folder = folder->nextSibling();
}
// if no folder was found, we must create a new one
if ( ! found )
{
folder = new KileProjectViewItem(parent,foldername);
KILE_DEBUG() << "new folder: " << parent->url().url() << endl;
folder->setFolder(pi->type());
folder->setType(KileType::Folder);
}
return folder;
}
void KileProjectView::add(const KileProject *project)
{
KileProjectViewItem *parent = new KileProjectViewItem(this, project);
parent->setType(KileType::Project);
parent->setURL(project->url());
parent->setOpen(true);
parent->setPixmap(0,SmallIcon("relation"));
makeTheConnection(parent);
//KileProjectViewItem *nonsrc = new KileProjectViewItem(parent, i18n("non-source"));
//parent->setNonSrc(nonsrc);
refreshProjectTree(project);
++m_nProjects;
}
KileProjectViewItem * KileProjectView::projectViewItemFor(const KURL & url)
{
KileProjectViewItem *item = 0;
//find project view item
item = static_cast<KileProjectViewItem*>(firstChild());
while ( item)
{
if ( (item->type() == KileType::Project) && (item->url() == url) )
break;
item = static_cast<KileProjectViewItem*>(item->nextSibling());
}
return item;
}
KileProjectViewItem * KileProjectView::itemFor(const KURL & url)
{
KileProjectViewItem *item=0;
TQListViewItemIterator it(this);
while (it.current())
{
item = static_cast<KileProjectViewItem*>(*it);
if (item->url() == url)
break;
++it;
}
return item;
}
KileProjectViewItem* KileProjectView::parentFor(const KileProjectItem *projitem, KileProjectViewItem *projvi)
{
//find parent projectviewitem of projitem
KileProjectItem *parpi = projitem->parent();
KileProjectViewItem *parpvi = projvi, *vi;
if (parpi) {
//find parent viewitem that has an URL parpi->url()
TQListViewItemIterator it( projvi );
KILE_DEBUG() << "\tlooking for " << parpi->url().path() << endl;
while (it.current())
{
vi = static_cast<KileProjectViewItem*>(*it);
KILE_DEBUG() << "\t\t" << vi->url().path() << endl;
if (vi->url() == parpi->url())
{
parpvi = vi;
KILE_DEBUG() << "\t\tfound" <<endl;
break;
}
++it;
}
KILE_DEBUG() << "\t\tnot found" << endl;
}
else {
KILE_DEBUG() << "\tlooking for folder type " << projitem->type() << endl;
for (parpvi = parpvi->firstChild(); parpvi; parpvi = parpvi->nextSibling())
{
if ( (parpvi->type() == KileType::Folder) && (parpvi->folder() == projitem->type()) )
{
KILE_DEBUG() << "\t\tfound" << endl;
break;
}
}
}
return (parpvi == 0) ? projvi : parpvi;
}
KileProjectViewItem* KileProjectView::add(KileProjectItem *projitem, KileProjectViewItem * projvi /* = 0*/)
{
KILE_DEBUG() << "\tKileProjectView::adding projectitem " << projitem->path() << endl;
const KileProject *project = projitem->project();
if (projvi == 0 )
{
projvi= projectViewItemFor(project->url());
}
KILE_DEBUG() << "\tparent projectviewitem " << projvi->url().fileName() << endl;
KileProjectViewItem *item, *parent;
switch (projitem->type()) {
case (KileProjectItem::Source):
item = new KileProjectViewItem(projvi, projitem);
item->setType(KileType::ProjectItem);
item->setPixmap(0,SmallIcon("projectitem"));
break;
case (KileProjectItem::Package):
parent = folder(projitem, projvi);
item = new KileProjectViewItem(parent, projitem);
item->setType(KileType::ProjectItem);
item->setPixmap(0,SmallIcon("projectitem"));
break;
case (KileProjectItem::ProjectFile):
default:
parent = folder(projitem, projvi);
item = new KileProjectViewItem(parent, projitem);
item->setType(KileType::ProjectExtra);
item->setPixmap(0,SmallIcon( (projitem->type()==KileProjectItem::ProjectFile) ? "kile" : "file" ));
break;
}
item->setArchiveState(projitem->archive());
item->setURL(projitem->url());
makeTheConnection(item);
projvi->sortChildItems(0,true);
return item;
}
void KileProjectView::addTree(KileProjectItem *projitem, KileProjectViewItem * projvi)
{
KileProjectViewItem * item = add(projitem, projvi);
if (projitem->firstChild())
addTree(projitem->firstChild(), item);
if (projitem->sibling())
addTree(projitem->sibling(), projvi);
}
void KileProjectView::refreshProjectTree(const KileProject *project)
{
KILE_DEBUG() << "\tKileProjectView::refreshProjectTree(" << project->name() << ")" << endl;
KileProjectViewItem *parent= projectViewItemFor(project->url());
//clean the tree
if (parent)
{
KILE_DEBUG() << "\tusing parent projectviewitem " << parent->url().fileName() << endl;
parent->setFolder(-1);
TQListViewItem *vi = parent->firstChild(), *next;
while (vi)
{
next = vi->nextSibling();
delete vi;
vi = next;
}
}
else
return;
//create the non-sources dir
//KileProjectViewItem *nonsrc = new KileProjectViewItem(parent, i18n("non-sources"));
//parent->setNonSrc(nonsrc);
TQPtrList<KileProjectItem> list = *(project->rootItems());
TQPtrListIterator<KileProjectItem> it(list);
while (it.current())
{
addTree(*it, parent);
++it;
}
parent->sortChildItems(0, true);
}
void KileProjectView::add(const KURL & url)
{
KILE_DEBUG() << "\tKileProjectView::adding item " << url.path() << endl;
//check if file is already present
TQListViewItemIterator it( this );
KileProjectViewItem *item;
while ( it.current())
{
item = static_cast<KileProjectViewItem*>(*it);
if ( (item->type() != KileType::Project) && (item->url() == url) )
return;
++it;
}
item = new KileProjectViewItem(this, url.fileName());
item->setType(KileType::File);
item->setURL(url);
makeTheConnection(item);
}
void KileProjectView::remove(const KileProject *project)
{
KileProjectViewItem *item = static_cast<KileProjectViewItem*>(firstChild());
while ( item)
{
if ( item->url() == project->url() )
{
takeItem(item);
delete item;
--m_nProjects;
break;
}
item = static_cast<KileProjectViewItem*>(item->nextSibling());
}
}
/**
* Removes a file from the projectview, does not remove project-items. Only files without a project.
**/
void KileProjectView::remove(const KURL &url)
{
KileProjectViewItem *item = static_cast<KileProjectViewItem*>(firstChild());
while ( item)
{
if ( (item->type() == KileType::File) && (item->url() == url) )
{
takeItem(item);
delete item;
break;
}
item = static_cast<KileProjectViewItem*>(item->nextSibling());
}
}
void KileProjectView::removeItem(const KileProjectItem *projitem, bool open)
{
TQListViewItemIterator it( this );
KileProjectViewItem *item;
while ( it.current())
{
item = static_cast<KileProjectViewItem*>(*it);
if ( (item->type() == KileType::ProjectItem) && (item->projectItem() == projitem) )
{
KILE_DEBUG() << "removing projectviewitem" << endl;
item->parent()->takeItem(item);
delete item;
}
++it;
}
if ( open )
{
item = new KileProjectViewItem(this, projitem->url().fileName());
item->setType(KileType::File);
item->setURL(projitem->url());
makeTheConnection(item);
}
}
bool KileProjectView::acceptDrag(TQDropEvent *e) const
{
return KURLDrag::canDecode(e); // only accept URL drops
}
#include "kileprojectview.moc"