File indexing completed on 2024-04-28 16:26:33

0001 /****************************************************************************************
0002     begin                : Tue Aug 12 2003
0003     copyright            : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)
0004                                2006 - 2010 by Michel Ludwig (michel.ludwig@kdemail.net)
0005  ****************************************************************************************/
0006 
0007 /***************************************************************************
0008  *                                                                         *
0009  *   This program is free software; you can redistribute it and/or modify  *
0010  *   it under the terms of the GNU General Public License as published by  *
0011  *   the Free Software Foundation; either version 2 of the License, or     *
0012  *   (at your option) any later version.                                   *
0013  *                                                                         *
0014  ***************************************************************************/
0015 
0016 #include "widgets/projectview.h"
0017 
0018 #include <QHeaderView>
0019 #include <QIcon>
0020 #include <KLocalizedString>
0021 #include <QList>
0022 #include <QMenu>
0023 #include <QMimeData>
0024 #include <QMimeDatabase>
0025 #include <QMimeType>
0026 #include <QUrl>
0027 
0028 #include <KActionMenu>
0029 #include <KIO/ApplicationLauncherJob>
0030 #include <KIO/JobUiDelegateFactory>
0031 #include <KIO/OpenUrlJob>
0032 #include <KApplicationTrader>
0033 #include <KJobUiDelegate>
0034 
0035 #include "kileinfo.h"
0036 #include "documentinfo.h"
0037 #include "kiledocmanager.h"
0038 #include <iostream>
0039 #include <typeinfo>
0040 
0041 const int KPV_ID_OPEN = 0, KPV_ID_SAVE = 1, KPV_ID_CLOSE = 2,
0042           KPV_ID_OPTIONS = 3, KPV_ID_ADD = 4, KPV_ID_REMOVE = 5,
0043           KPV_ID_BUILDTREE = 6, KPV_ID_ARCHIVE = 7, KPV_ID_ADDFILES = 8,
0044           KPV_ID_INCLUDE = 9, KPV_ID_OPENWITH = 10, KPV_ID_OPENALLFILES = 11;
0045 
0046 namespace KileWidget {
0047 
0048 /*
0049  * ProjectViewItem
0050  */
0051 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, KileProjectItem *item, bool ar)
0052     : QTreeWidgetItem(parent, QStringList(item->url().fileName())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item)
0053 {
0054     setArchiveState(ar);
0055 }
0056 
0057 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, QTreeWidgetItem *after, KileProjectItem *item, bool ar)
0058     : QTreeWidgetItem(parent, after), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item)
0059 {
0060     setText(0, item->url().fileName());
0061     setArchiveState(ar);
0062 }
0063 
0064 ProjectViewItem::ProjectViewItem(QTreeWidgetItem *parent, KileProjectItem *item, bool ar)
0065     : QTreeWidgetItem(parent, QStringList(item->url().fileName())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item)
0066 {
0067     setArchiveState(ar);
0068 }
0069 
0070 //use this to create folders
0071 ProjectViewItem::ProjectViewItem(QTreeWidgetItem *parent, const QString& name)
0072     : QTreeWidgetItem(parent, QStringList(name)), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR)
0073 {
0074 }
0075 
0076 //use this to create non-project files
0077 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, const QString& name)
0078     : QTreeWidgetItem(parent, QStringList(name)), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR)
0079 {
0080 }
0081 
0082 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, const KileProject *project)
0083     : QTreeWidgetItem(parent, QStringList(project->name())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR)
0084 {
0085 }
0086 
0087 ProjectViewItem::~ProjectViewItem()
0088 {
0089     KILE_DEBUG_MAIN << "DELETING PROJVIEWITEM " << m_url.fileName();
0090 }
0091 
0092 KileProjectItem* ProjectViewItem::projectItem()
0093 {
0094     return m_projectItem;
0095 }
0096 
0097 ProjectViewItem* ProjectViewItem::parent()
0098 {
0099     return dynamic_cast<ProjectViewItem*>(QTreeWidgetItem::parent());
0100 }
0101 
0102 ProjectViewItem* ProjectViewItem::firstChild()
0103 {
0104     return dynamic_cast<ProjectViewItem*>(QTreeWidgetItem::child(0));
0105 }
0106 
0107 void ProjectViewItem::setInfo(KileDocument::Info *docinfo)
0108 {
0109     m_docinfo = docinfo;
0110 }
0111 
0112 KileDocument::Info* ProjectViewItem::getInfo()
0113 {
0114     return m_docinfo;
0115 }
0116 
0117 void ProjectViewItem::setType(KileType::ProjectView type)
0118 {
0119     m_type = type;
0120 }
0121 
0122 KileType::ProjectView ProjectViewItem::type() const
0123 {
0124     return m_type;
0125 }
0126 
0127 void ProjectViewItem::urlChanged(const QUrl &url)
0128 {
0129     // don't allow empty URLs
0130     if(!url.isEmpty()) {
0131         setURL(url);
0132         setText(0, url.fileName());
0133     }
0134 }
0135 
0136 void ProjectViewItem::nameChanged(const QString & name)
0137 {
0138     setText(0, name);
0139 }
0140 
0141 void ProjectViewItem::isrootChanged(bool isroot)
0142 {
0143     KILE_DEBUG_MAIN << "SLOT isrootChanged " << text(0) << " to " << isroot;
0144     if(isroot) {
0145         setIcon(0, QIcon::fromTheme("masteritem"));
0146     }
0147     else {
0148         if(m_projectItem && m_projectItem->type() == KileProjectItem::ProjectFile) {
0149             setIcon(0, QIcon::fromTheme("kile"));
0150         }
0151         else if(m_projectItem && m_projectItem->type() == KileProjectItem::Bibliography) {
0152             setIcon(0, QIcon::fromTheme("viewbib"));
0153         }
0154         else if(type() == KileType::ProjectItem) {
0155             setIcon(0, QIcon::fromTheme("projectitem"));
0156         }
0157         else {
0158             setIcon(0, QIcon::fromTheme("file"));
0159         }
0160     }
0161 }
0162 
0163 void ProjectViewItem::slotURLChanged(KileDocument::Info*, const QUrl &url)
0164 {
0165     urlChanged(url);
0166 }
0167 
0168 bool ProjectViewItem::operator<(const QTreeWidgetItem& other) const
0169 {
0170     try {
0171         const ProjectViewItem& otherItem = dynamic_cast<const ProjectViewItem&>(other);
0172 
0173         // order in the tree:
0174         // - first, root items without container (sorted in ascending order)
0175         // - then, container items in fixed order (images, packages, other, projectfile)
0176         if(otherItem.type() == KileType::Folder) {
0177             if(type() != KileType::Folder) {
0178                 return true;
0179             }
0180             else {
0181                 // 'm_folder' is set to a type from 'KileProject::Type'
0182                 // we want: Image < Package < Other < ProjectFile
0183                 switch(m_folder) {
0184                 case KileProjectItem::Image:
0185                     return true;
0186 
0187                 case KileProjectItem::Package:
0188                     return (otherItem.m_folder == KileProjectItem::Image) ? false : true;
0189 
0190                 case KileProjectItem::Other:
0191                     return (otherItem.m_folder == KileProjectItem::Image
0192                             || otherItem.m_folder == KileProjectItem::Package) ? false : true;
0193 
0194                 case KileProjectItem::ProjectFile:
0195                     return false;
0196 
0197                 default: // dummy
0198                     return false;
0199                 }
0200             }
0201         }
0202         else if(type() == KileType::Folder) {
0203             return false;
0204         }
0205         else {
0206             return QTreeWidgetItem::operator<(other);
0207         }
0208     }
0209     catch(std::bad_cast&) {
0210         return QTreeWidgetItem::operator<(other);
0211     }
0212 }
0213 
0214 void ProjectViewItem::setURL(const QUrl &url)
0215 {
0216     m_url = url;
0217 }
0218 
0219 const QUrl &ProjectViewItem::url()
0220 {
0221     return m_url;
0222 }
0223 
0224 void ProjectViewItem::setArchiveState(bool ar)
0225 {
0226     setText(1, ar ? "*" : "");
0227 }
0228 
0229 void ProjectViewItem::setFolder(int folder)
0230 {
0231     m_folder = folder;
0232 }
0233 
0234 int ProjectViewItem::folder() const
0235 {
0236     return m_folder;
0237 }
0238 
0239 /*
0240  * ProjectView
0241  */
0242 ProjectView::ProjectView(QWidget *parent, KileInfo *ki) : QTreeWidget(parent), m_ki(ki), m_nProjects(0)
0243 {
0244     setColumnCount(2);
0245     QStringList labelList;
0246     labelList << i18n("Files & Projects") << i18n("Include in Archive");
0247     setHeaderLabels(labelList);
0248     setColumnWidth(1, 10);
0249 
0250     setFocusPolicy(Qt::ClickFocus);
0251     header()->hide();
0252     header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0253     setRootIsDecorated(true);
0254     setAllColumnsShowFocus(true);
0255     setSelectionMode(QTreeWidget::SingleSelection);
0256 
0257     connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotClicked(QTreeWidgetItem*)));
0258     setAcceptDrops(true);
0259 }
0260 
0261 void ProjectView::slotClicked(QTreeWidgetItem *item)
0262 {
0263     if(!item) {
0264         item = currentItem();
0265     }
0266 
0267     ProjectViewItem *itm = static_cast<ProjectViewItem*>(item);
0268     if(itm) {
0269         if(itm->type() == KileType::File) {
0270             emit(fileSelected(itm->url()));
0271         }
0272         else if(itm->type() == KileType::ProjectItem) {
0273             emit(fileSelected(itm->projectItem()));
0274         }
0275         else if(itm->type() != KileType::Folder) {
0276             // don't open project configuration files (*.kilepr)
0277             if(itm->url().toLocalFile().right(7) != ".kilepr") {
0278                 //determine mimeType and open file with preferred application
0279                 QMimeDatabase db;
0280                 QMimeType pMime = db.mimeTypeForUrl(itm->url());
0281                 if(pMime.name().startsWith(QLatin1String("text/"))) {
0282                     emit(fileSelected(itm->url()));
0283                 }
0284                 else {
0285                     auto *job = new KIO::OpenUrlJob(itm->url(), pMime.name());
0286                     job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0287                     job->start();
0288                 }
0289             }
0290         }
0291         clearSelection();
0292     }
0293 }
0294 
0295 void ProjectView::slotFile(int id)
0296 {
0297     ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(currentItem());
0298     if(item) {
0299         if(item->type() == KileType::File) {
0300             switch(id) {
0301             case KPV_ID_OPEN:
0302                 emit(fileSelected(item->url()));
0303                 break;
0304             case KPV_ID_SAVE:
0305                 emit(saveURL(item->url()));
0306                 break;
0307             case KPV_ID_ADD:
0308                 emit(addToProject(item->url()));
0309                 break;
0310             case KPV_ID_CLOSE:
0311                 emit(closeURL(item->url()));
0312                 return; //don't access "item" later on
0313             default:
0314                 break;
0315             }
0316         }
0317     }
0318 }
0319 
0320 void ProjectView::slotProjectItem(int id)
0321 {
0322     ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(currentItem());
0323     if(item) {
0324         if(item->type() == KileType::ProjectItem || item->type() == KileType::ProjectExtra) {
0325             switch(id) {
0326             case KPV_ID_OPEN:
0327                 emit(fileSelected(item->projectItem()));
0328                 break;
0329             case KPV_ID_SAVE:
0330                 emit(saveURL(item->url()));
0331                 break;
0332             case KPV_ID_REMOVE:
0333                 emit(removeFromProject(item->projectItem()));
0334                 break;
0335             case KPV_ID_INCLUDE :
0336                 if(item->text(1) == "*") {
0337                     item->setText(1, "");
0338                 }
0339                 else {
0340                     item->setText(1, "*");
0341                 }
0342                 emit(toggleArchive(item->projectItem()));
0343                 break;
0344             case KPV_ID_CLOSE:
0345                 emit(closeURL(item->url()));
0346                 break; //we can access "item" later as it isn't deleted
0347             case KPV_ID_OPENWITH:
0348             {
0349                 auto *job = new KIO::ApplicationLauncherJob();
0350                 job->setUrls(QList<QUrl>() << item->url());
0351                 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0352                 job->start();
0353                 break;
0354             }
0355             default:
0356                 break;
0357             }
0358         }
0359     }
0360 }
0361 
0362 void ProjectView::slotProject(int id)
0363 {
0364     ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(currentItem());
0365     if(item) {
0366         if(item->type() == KileType::Project) {
0367             switch(id) {
0368             case KPV_ID_BUILDTREE:
0369                 emit(buildProjectTree(item->url()));
0370                 break;
0371             case KPV_ID_OPTIONS:
0372                 emit(projectOptions(item->url()));
0373                 break;
0374             case KPV_ID_CLOSE:
0375                 emit(closeProject(item->url()));
0376                 return; //don't access "item" later on
0377             case KPV_ID_ARCHIVE:
0378                 emit(projectArchive(item->url()));
0379                 break;
0380             case KPV_ID_ADDFILES:
0381                 emit(addFiles(item->url()));
0382                 break;
0383             case KPV_ID_OPENALLFILES:
0384                 emit(openAllFiles(item->url()));
0385                 break;
0386             default:
0387                 break;
0388             }
0389         }
0390     }
0391 }
0392 
0393 void ProjectView::slotRun(int id)
0394 {
0395     ProjectViewItem *itm = dynamic_cast<ProjectViewItem*>(currentItem());
0396 
0397     if(!itm) {
0398         return;
0399     }
0400 
0401     if(id == 0) {
0402         // open with dialog
0403         auto *job = new KIO::ApplicationLauncherJob();
0404         job->setUrls(QList<QUrl>() << itm->url());
0405         job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0406         job->start();
0407     }
0408     else {
0409         auto *job = new KIO::ApplicationLauncherJob(m_offerList[id - 1]);
0410         job->setUrls(QList<QUrl>() << itm->url());
0411         job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0412         job->start();
0413     }
0414 
0415     itm->setSelected(false);
0416 }
0417 
0418 void ProjectView::makeTheConnection(ProjectViewItem *item, KileDocument::TextInfo *textInfo)
0419 {
0420     KILE_DEBUG_MAIN << "\tmakeTheConnection " << item->text(0);
0421 
0422     if (item->type() == KileType::Project) {
0423         KileProject *project = m_ki->docManager()->projectFor(item->url());
0424         if (!project) {
0425             qWarning() << "makeTheConnection COULD NOT FIND AN PROJECT OBJECT FOR " << item->url().toLocalFile();
0426         }
0427         else {
0428             connect(project, SIGNAL(nameChanged(QString)), item, SLOT(nameChanged(QString)));
0429         }
0430     }
0431     else {
0432         if(!textInfo) {
0433             textInfo = m_ki->docManager()->textInfoFor(item->url().toLocalFile());
0434             if(!textInfo) {
0435                 KILE_DEBUG_MAIN << "\tmakeTheConnection COULD NOT FIND A DOCINFO";
0436                 return;
0437             }
0438         }
0439         item->setInfo(textInfo);
0440         connect(textInfo, SIGNAL(urlChanged(KileDocument::Info*,QUrl)),  item, SLOT(slotURLChanged(KileDocument::Info*,QUrl)));
0441         connect(textInfo, SIGNAL(isrootChanged(bool)), item, SLOT(isrootChanged(bool)));
0442         //set the pixmap
0443         item->isrootChanged(textInfo->isLaTeXRoot());
0444     }
0445 }
0446 
0447 ProjectViewItem* ProjectView::folder(const KileProjectItem *pi, ProjectViewItem *item)
0448 {
0449     ProjectViewItem *parent = parentFor(pi, item);
0450 
0451     if(!parent) {
0452         qCritical() << "no parent for " << pi->url().toLocalFile();
0453         return Q_NULLPTR;
0454     }
0455 
0456     // we have already found the parent folder
0457     if(parent->type() == KileType::Folder) {
0458         return parent;
0459     }
0460 
0461     // we are looking at the children, if there is an existing folder for this type
0462     ProjectViewItem *folder;
0463 
0464     // determine the foldername for this type
0465     QString foldername;
0466     switch(pi->type()) {
0467     case (KileProjectItem::ProjectFile):
0468         foldername = i18n("Project File");
0469         break;
0470     case (KileProjectItem::Package):
0471         foldername = i18n("Packages");
0472         break;
0473     case (KileProjectItem::Image):
0474         foldername = i18n("Images");
0475         break;
0476     case (KileProjectItem::Bibliography):
0477         foldername = i18n("Bibliography");
0478         break;
0479     case (KileProjectItem::Other):
0480     default :
0481         foldername = i18n("Other");
0482         break;
0483     }
0484 
0485     // if there already a folder for this type on this level?
0486     bool found = false;
0487     QTreeWidgetItemIterator it(parent);
0488     ++it; // skip 'parent'
0489     while(*it) {
0490         folder = dynamic_cast<ProjectViewItem*>(*it);
0491         if(folder && folder->text(0) == foldername) {
0492             found = true;
0493             break;
0494         }
0495         ++it;
0496     }
0497 
0498     // if no folder was found, we must create a new one
0499     if(!found) {
0500         folder = new ProjectViewItem(parent, foldername);
0501         KILE_DEBUG_MAIN << "new folder: parent=" << parent->url().url()
0502                         << ", foldername=" << foldername;
0503 
0504         folder->setFolder(pi->type());
0505         folder->setType(KileType::Folder);
0506     }
0507 
0508     return folder;
0509 }
0510 
0511 void ProjectView::add(const KileProject *project)
0512 {
0513     ProjectViewItem *parent = new ProjectViewItem(this, project);
0514 
0515     parent->setType(KileType::Project);
0516     parent->setURL(project->url());
0517     parent->setExpanded(true);
0518     parent->setIcon(0, QIcon::fromTheme("relation"));
0519     makeTheConnection(parent);
0520 
0521     //ProjectViewItem *nonsrc = new ProjectViewItem(parent, i18n("non-source"));
0522     //parent->setNonSrc(nonsrc);
0523 
0524     refreshProjectTree(project);
0525 
0526     ++m_nProjects;
0527 }
0528 
0529 ProjectViewItem* ProjectView::projectViewItemFor(const QUrl &url)
0530 {
0531     ProjectViewItem *item = Q_NULLPTR;
0532 
0533     //find project view item
0534     QTreeWidgetItemIterator it(this);
0535     while(*it) {
0536         item = dynamic_cast<ProjectViewItem*>(*it);
0537         if(item && (item->type() == KileType::Project) && (item->url() == url)) {
0538             break;
0539         }
0540         ++it;
0541     }
0542 
0543     return item;
0544 }
0545 
0546 ProjectViewItem* ProjectView::itemFor(const QUrl &url)
0547 {
0548     ProjectViewItem *item = Q_NULLPTR;
0549 
0550     QTreeWidgetItemIterator it(this);
0551     while(*it) {
0552         item = static_cast<ProjectViewItem*>(*it);
0553         if (item->url() == url) {
0554             break;
0555         }
0556         ++it;
0557     }
0558 
0559     return item;
0560 }
0561 
0562 ProjectViewItem* ProjectView::parentFor(const KileProjectItem *projitem, ProjectViewItem *projvi)
0563 {
0564     //find parent projectviewitem of projitem
0565     KileProjectItem *parpi = projitem->parent();
0566     ProjectViewItem *parpvi = projvi, *vi;
0567 
0568     if (parpi) {
0569         //find parent viewitem that has an URL parpi->url()
0570         QTreeWidgetItemIterator it(projvi);
0571         KILE_DEBUG_MAIN << "\tlooking for " << parpi->url().toLocalFile();
0572         while(*it) {
0573             vi = static_cast<ProjectViewItem*>(*it);
0574             KILE_DEBUG_MAIN << "\t\t" << vi->url().toLocalFile();
0575             if (vi->url() == parpi->url()) {
0576                 parpvi = vi;
0577                 KILE_DEBUG_MAIN << "\t\tfound" << Qt::endl;
0578                 break;
0579             }
0580             ++it;
0581         }
0582 
0583         KILE_DEBUG_MAIN << "\t\tnot found";
0584     }
0585     else {
0586         KILE_DEBUG_MAIN << "\tlooking for folder type " << projitem->type();
0587         QTreeWidgetItemIterator it(projvi);
0588         ++it; // skip projvi
0589         while(*it) {
0590             ProjectViewItem *child = dynamic_cast<ProjectViewItem*>(*it);
0591             if(child && (child->type() == KileType::Folder) && (child->folder() == projitem->type())) {
0592                 KILE_DEBUG_MAIN << "\t\tfound";
0593                 parpvi = child;
0594                 break;
0595             }
0596             ++it;
0597         }
0598     }
0599 
0600     return (!parpvi) ? projvi : parpvi;
0601 }
0602 
0603 ProjectViewItem* ProjectView::add(KileProjectItem *projitem, ProjectViewItem *projvi /* = Q_NULLPTR */)
0604 {
0605     KILE_DEBUG_MAIN << "\tprojectitem=" << projitem->path()
0606                     << " projvi=" << projvi;
0607     const KileProject *project = projitem->project();
0608 
0609     if (!projvi) {
0610         projvi = projectViewItemFor(project->url());
0611     }
0612 
0613     KILE_DEBUG_MAIN << "\tparent projectviewitem " << projvi->url().fileName();
0614 
0615     ProjectViewItem *item = Q_NULLPTR, *parent = Q_NULLPTR;
0616 
0617     switch (projitem->type()) {
0618     case (KileProjectItem::Source):
0619         item = new ProjectViewItem(projvi, projitem);
0620         item->setType(KileType::ProjectItem);
0621         item->setIcon(0, QIcon::fromTheme("projectitem"));
0622         break;
0623     case (KileProjectItem::Package):
0624         parent = folder(projitem, projvi);
0625         item = new ProjectViewItem(parent, projitem);
0626         item->setType(KileType::ProjectItem);
0627         item->setIcon(0, QIcon::fromTheme("projectitem"));
0628         break;
0629     default:
0630         parent = folder(projitem, projvi);
0631         item = new ProjectViewItem(parent, projitem);
0632         item->setType(KileType::ProjectExtra);
0633         if(projitem->type() == KileProjectItem::ProjectFile) {
0634             item->setIcon(0, QIcon::fromTheme("kile"));
0635         }
0636         else if(projitem->type() == KileProjectItem::Bibliography) {
0637             item->setIcon(0, QIcon::fromTheme("viewbib"));
0638         }
0639         else {
0640             item->setIcon(0, QIcon::fromTheme("file"));
0641         }
0642         break;
0643     }
0644 
0645     item->setArchiveState(projitem->archive());
0646     item->setURL(projitem->url());
0647     makeTheConnection(item, projitem->getInfo());
0648 
0649     projvi->sortChildren(0, Qt::AscendingOrder);
0650     // seems to be necessary to get a correct refreh (Qt 4.4.3)
0651     bool expanded = projvi->isExpanded();
0652     projvi->setExpanded(!expanded);
0653     projvi->setExpanded(expanded);
0654 
0655     return item;
0656 }
0657 
0658 void ProjectView::addTree(KileProjectItem *projitem, ProjectViewItem *projvi)
0659 {
0660     KILE_DEBUG_MAIN << "projitem=" << projitem
0661                     << "projvi=" << projvi;
0662     ProjectViewItem * item = add(projitem, projvi);
0663 
0664     if(projitem->firstChild()) {
0665         addTree(projitem->firstChild(), item);
0666     }
0667 
0668     if (projitem->sibling()) {
0669         addTree(projitem->sibling(), projvi);
0670     }
0671 }
0672 
0673 void ProjectView::refreshProjectTree(const KileProject *project)
0674 {
0675     KILE_DEBUG_MAIN << "\tProjectView::refreshProjectTree(" << project->name() << ")";
0676     ProjectViewItem *parent= projectViewItemFor(project->url());
0677 
0678     //clean the tree
0679     if(parent) {
0680         KILE_DEBUG_MAIN << "\tusing parent projectviewitem " << parent->url().fileName();
0681         parent->setFolder(-1);
0682         QList<QTreeWidgetItem*> children = parent->takeChildren();
0683         for(QList<QTreeWidgetItem*>::iterator it = children.begin();
0684                 it != children.end(); ++it) {
0685             delete(*it);
0686         }
0687     }
0688     else {
0689         return;
0690     }
0691 
0692     //create the non-sources dir
0693     //ProjectViewItem *nonsrc = new ProjectViewItem(parent, i18n("non-sources"));
0694     //parent->setNonSrc(nonsrc);
0695 
0696     QList<KileProjectItem*> list = project->rootItems();
0697     for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
0698         addTree(*it, parent);
0699     }
0700 
0701     parent->sortChildren(0, Qt::AscendingOrder);
0702     // seems to be necessary to get a correct refreh (Qt 4.4.3)
0703     bool expanded = parent->isExpanded();
0704     parent->setExpanded(!expanded);
0705     parent->setExpanded(expanded);
0706 }
0707 
0708 void ProjectView::add(const QUrl &url)
0709 {
0710     KILE_DEBUG_MAIN << "\tProjectView::adding item " << url.toLocalFile();
0711     //check if file is already present
0712     QTreeWidgetItemIterator it(this);
0713     ProjectViewItem *item;
0714     while(*it) {
0715         item = static_cast<ProjectViewItem*>(*it);
0716         if((item->type() != KileType::Project) && (item->url() == url)) {
0717             return;
0718         }
0719         ++it;
0720     }
0721 
0722     item = new ProjectViewItem(this, url.fileName());
0723     item->setType(KileType::File);
0724     item->setURL(url);
0725     makeTheConnection(item);
0726 }
0727 
0728 void ProjectView::remove(const KileProject *project)
0729 {
0730     for(int i = 0; i < topLevelItemCount(); ++i) {
0731         ProjectViewItem *item = static_cast<ProjectViewItem*>(topLevelItem(i));
0732 
0733         if(item->url() == project->url()) {
0734             item->setParent(Q_NULLPTR);
0735             delete item;
0736             --m_nProjects;
0737             break;
0738         }
0739     }
0740 }
0741 
0742 /**
0743  * Removes a file from the projectview, does not remove project-items. Only files without a project.
0744  **/
0745 void ProjectView::remove(const QUrl &url)
0746 {
0747     for(int i = 0; i < topLevelItemCount(); ++i) {
0748         ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(topLevelItem(i));
0749 
0750         if(item && (item->type() == KileType::File) && (item->url() == url)) {
0751             item->setParent(Q_NULLPTR);
0752             delete item;
0753             break;
0754         }
0755     }
0756 }
0757 
0758 void ProjectView::removeItem(const KileProjectItem *projitem, bool open)
0759 {
0760     QTreeWidgetItemIterator it(this);
0761     ProjectViewItem *item;
0762     while(*it) {
0763         item = dynamic_cast<ProjectViewItem*>(*it);
0764         if(item && (item->type() == KileType::ProjectItem) && (item->projectItem() == projitem)) {
0765             KILE_DEBUG_MAIN << "removing projectviewitem";
0766             static_cast<QTreeWidgetItem*>(item->parent())->removeChild(item);
0767             delete item;
0768         }
0769         ++it;
0770     }
0771 
0772     if(open) {
0773         item = new ProjectViewItem(this, projitem->url().fileName());
0774         item->setType(KileType::File);
0775         item->setURL(projitem->url());
0776         makeTheConnection(item);
0777     }
0778 
0779 }
0780 
0781 void ProjectView::contextMenuEvent(QContextMenuEvent *event)
0782 {
0783     QMenu popup;
0784     QAction *action = Q_NULLPTR;
0785 
0786     QTreeWidgetItem* treeWidgetItem = itemAt(event->pos());
0787     if(!treeWidgetItem) {
0788         return;
0789     }
0790 
0791     ProjectViewItem *projectViewItem = dynamic_cast<ProjectViewItem*>(treeWidgetItem);
0792     if(!projectViewItem) {
0793         return;
0794     }
0795 
0796     if(projectViewItem->type() == KileType::Folder) {
0797         return;
0798     }
0799 
0800     bool insertsep = false;
0801     bool isKilePrFile = false;
0802     if(projectViewItem->type() != KileType::Project && projectViewItem->projectItem()
0803             && projectViewItem->projectItem()->project()) {
0804         isKilePrFile = projectViewItem->projectItem()->project()->url() == projectViewItem->url();
0805     }
0806 
0807     if(projectViewItem->type() == KileType::ProjectExtra && !isKilePrFile) {
0808         QMenu *servicesMenu = popup.addMenu(QIcon::fromTheme("fork"), i18n("&Open With"));
0809         QMimeDatabase db;
0810         m_offerList = KApplicationTrader::queryByMimeType(db.mimeTypeForUrl(projectViewItem->url()).name());
0811         for (int i = 0; i < m_offerList.count(); ++i) {
0812             action = new QAction(servicesMenu);
0813             action->setIcon(QIcon::fromTheme(m_offerList[i]->icon()));
0814             action->setText(m_offerList[i]->name());
0815             connect(action, &QAction::triggered, this, [this, i] { slotRun(i + 1); });
0816             servicesMenu->addAction(action);
0817         }
0818 
0819         servicesMenu->addSeparator();
0820         servicesMenu->addAction(i18n("Other..."), this, [this] { slotRun(0); });
0821         insertsep = true;
0822     }
0823 
0824     if (projectViewItem->type() == KileType::File || projectViewItem->type() == KileType::ProjectItem) {
0825         if(!m_ki->isOpen(projectViewItem->url())) {
0826             popup.addAction(QIcon::fromTheme("document-open"), i18n("&Open"), this, [this] { slotProjectItem(KPV_ID_OPEN); });
0827         }
0828         else {
0829             popup.addAction(QIcon::fromTheme("document-save"), i18n("&Save"), this, [this] { slotProjectItem(KPV_ID_SAVE); });
0830         }
0831         insertsep = true;
0832     }
0833 
0834     if(projectViewItem->type() == KileType::File) {
0835         if(m_nProjects > 0) {
0836             if(insertsep) {
0837                 popup.addSeparator();
0838             }
0839             popup.addAction(QIcon::fromTheme("project_add"), i18n("&Add to Project"), this, [this] { slotProjectItem(KPV_ID_ADD); });
0840             insertsep = true;
0841         }
0842     }
0843     else if(projectViewItem->type() == KileType::ProjectItem || projectViewItem->type() == KileType::ProjectExtra) {
0844         KileProjectItem *pi = projectViewItem->projectItem();
0845         if(pi) {
0846             if(insertsep) {
0847                 popup.addSeparator();
0848             }
0849             action = popup.addAction(i18n("&Include in Archive"), this, [this] { slotProjectItem(KPV_ID_INCLUDE); });
0850             action->setCheckable(true);
0851             action->setChecked(pi->archive());
0852             insertsep = true;
0853         }
0854         if(!isKilePrFile) {
0855             if(insertsep) {
0856                 popup.addSeparator();
0857             }
0858             popup.addAction(QIcon::fromTheme("project_remove"),i18n("&Remove From Project"), this, [this] { slotProjectItem(KPV_ID_REMOVE); });
0859             insertsep = true;
0860         }
0861     }
0862     else if(projectViewItem->type() == KileType::Project) {
0863         if(insertsep) {
0864             popup.addSeparator();
0865         }
0866         popup.addAction(i18n("A&dd Files..."), this, [this] { slotProject(KPV_ID_ADDFILES); });
0867         popup.addSeparator();
0868         popup.addAction(i18n("Open All &Project Files"), this, [this] { slotProject(KPV_ID_OPENALLFILES); });
0869         popup.addSeparator();
0870         popup.addAction(QIcon::fromTheme("view-refresh"),i18n("Refresh Project &Tree"), this, [this] { slotProject(KPV_ID_BUILDTREE); });
0871         popup.addAction(QIcon::fromTheme("configure"), i18n("Project &Options"), this, [this] { slotProject(KPV_ID_OPTIONS); });
0872         popup.addAction(i18n("&Archive"), this, [this] { slotProject(KPV_ID_ARCHIVE); });
0873         insertsep = true;
0874     }
0875 
0876     if((projectViewItem->type() == KileType::File) || (projectViewItem->type() == KileType::ProjectItem)
0877             || (projectViewItem->type()== KileType::Project)) {
0878         if(insertsep) {
0879             popup.addSeparator();
0880         }
0881         if(projectViewItem->type() == KileType::Project) {
0882             popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), this, [this] { slotProject(KPV_ID_CLOSE); });
0883         }
0884         else {
0885             popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), this, [this] { slotProjectItem(KPV_ID_CLOSE); });
0886         }
0887     }
0888 
0889     popup.exec(event->globalPos());
0890     m_offerList.clear();
0891 }
0892 
0893 void ProjectView::dragEnterEvent(QDragEnterEvent *event)
0894 {
0895     if(event->mimeData()->hasUrls()) { // only accept URL drags
0896         event->acceptProposedAction();
0897     }
0898 }
0899 
0900 void ProjectView::dragMoveEvent(QDragMoveEvent *event)
0901 {
0902     if(event->mimeData()->hasUrls()) { // only accept URL drags
0903         event->acceptProposedAction();
0904     }
0905 }
0906 
0907 void ProjectView::dropEvent(QDropEvent *event)
0908 {
0909     m_ki->docManager()->openDroppedURLs(event);
0910 }
0911 
0912 }
0913