1 /****************************************************************************************
2     begin                : Tue Aug 12 2003
3     copyright            : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)
4                                2006 - 2010 by Michel Ludwig (michel.ludwig@kdemail.net)
5  ****************************************************************************************/
6 
7 /***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #include "widgets/projectview.h"
17 
18 #include <QHeaderView>
19 #include <QIcon>
20 #include <KLocalizedString>
21 #include <QList>
22 #include <QMenu>
23 #include <QMimeData>
24 #include <QMimeDatabase>
25 #include <QMimeType>
26 #include <QUrl>
27 
28 #include <KActionMenu>
29 #include <KMimeTypeTrader>
30 #include <KRun>
31 
32 #include "kileinfo.h"
33 #include "documentinfo.h"
34 #include "kiledocmanager.h"
35 #include <iostream>
36 #include <typeinfo>
37 
38 const int KPV_ID_OPEN = 0, KPV_ID_SAVE = 1, KPV_ID_CLOSE = 2,
39           KPV_ID_OPTIONS = 3, KPV_ID_ADD = 4, KPV_ID_REMOVE = 5,
40           KPV_ID_BUILDTREE = 6, KPV_ID_ARCHIVE = 7, KPV_ID_ADDFILES = 8,
41           KPV_ID_INCLUDE = 9, KPV_ID_OPENWITH = 10, KPV_ID_OPENALLFILES = 11;
42 
43 namespace KileWidget {
44 
45 /*
46  * ProjectViewItem
47  */
ProjectViewItem(QTreeWidget * parent,KileProjectItem * item,bool ar)48 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, KileProjectItem *item, bool ar)
49     : QTreeWidgetItem(parent, QStringList(item->url().fileName())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item)
50 {
51     setArchiveState(ar);
52 }
53 
ProjectViewItem(QTreeWidget * parent,QTreeWidgetItem * after,KileProjectItem * item,bool ar)54 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, QTreeWidgetItem *after, KileProjectItem *item, bool ar)
55     : QTreeWidgetItem(parent, after), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item)
56 {
57     setText(0, item->url().fileName());
58     setArchiveState(ar);
59 }
60 
ProjectViewItem(QTreeWidgetItem * parent,KileProjectItem * item,bool ar)61 ProjectViewItem::ProjectViewItem(QTreeWidgetItem *parent, KileProjectItem *item, bool ar)
62     : QTreeWidgetItem(parent, QStringList(item->url().fileName())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(item)
63 {
64     setArchiveState(ar);
65 }
66 
67 //use this to create folders
ProjectViewItem(QTreeWidgetItem * parent,const QString & name)68 ProjectViewItem::ProjectViewItem(QTreeWidgetItem *parent, const QString& name)
69     : QTreeWidgetItem(parent, QStringList(name)), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR)
70 {
71 }
72 
73 //use this to create non-project files
ProjectViewItem(QTreeWidget * parent,const QString & name)74 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, const QString& name)
75     : QTreeWidgetItem(parent, QStringList(name)), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR)
76 {
77 }
78 
ProjectViewItem(QTreeWidget * parent,const KileProject * project)79 ProjectViewItem::ProjectViewItem(QTreeWidget *parent, const KileProject *project)
80     : QTreeWidgetItem(parent, QStringList(project->name())), m_docinfo(Q_NULLPTR), m_folder(-1), m_projectItem(Q_NULLPTR)
81 {
82 }
83 
~ProjectViewItem()84 ProjectViewItem::~ProjectViewItem()
85 {
86     KILE_DEBUG_MAIN << "DELETING PROJVIEWITEM " << m_url.fileName();
87 }
88 
projectItem()89 KileProjectItem* ProjectViewItem::projectItem()
90 {
91     return m_projectItem;
92 }
93 
parent()94 ProjectViewItem* ProjectViewItem::parent()
95 {
96     return dynamic_cast<ProjectViewItem*>(QTreeWidgetItem::parent());
97 }
98 
firstChild()99 ProjectViewItem* ProjectViewItem::firstChild()
100 {
101     return dynamic_cast<ProjectViewItem*>(QTreeWidgetItem::child(0));
102 }
103 
setInfo(KileDocument::Info * docinfo)104 void ProjectViewItem::setInfo(KileDocument::Info *docinfo)
105 {
106     m_docinfo = docinfo;
107 }
108 
getInfo()109 KileDocument::Info* ProjectViewItem::getInfo()
110 {
111     return m_docinfo;
112 }
113 
setType(KileType::ProjectView type)114 void ProjectViewItem::setType(KileType::ProjectView type)
115 {
116     m_type = type;
117 }
118 
type() const119 KileType::ProjectView ProjectViewItem::type() const
120 {
121     return m_type;
122 }
123 
urlChanged(const QUrl & url)124 void ProjectViewItem::urlChanged(const QUrl &url)
125 {
126     // don't allow empty URLs
127     if(!url.isEmpty()) {
128         setURL(url);
129         setText(0, url.fileName());
130     }
131 }
132 
nameChanged(const QString & name)133 void ProjectViewItem::nameChanged(const QString & name)
134 {
135     setText(0, name);
136 }
137 
isrootChanged(bool isroot)138 void ProjectViewItem::isrootChanged(bool isroot)
139 {
140     KILE_DEBUG_MAIN << "SLOT isrootChanged " << text(0) << " to " << isroot;
141     if(isroot) {
142         setIcon(0, QIcon::fromTheme("masteritem"));
143     }
144     else {
145         if(m_projectItem && m_projectItem->type() == KileProjectItem::ProjectFile) {
146             setIcon(0, QIcon::fromTheme("kile"));
147         }
148         else if(m_projectItem && m_projectItem->type() == KileProjectItem::Bibliography) {
149             setIcon(0, QIcon::fromTheme("viewbib"));
150         }
151         else if(type() == KileType::ProjectItem) {
152             setIcon(0, QIcon::fromTheme("projectitem"));
153         }
154         else {
155             setIcon(0, QIcon::fromTheme("file"));
156         }
157     }
158 }
159 
slotURLChanged(KileDocument::Info *,const QUrl & url)160 void ProjectViewItem::slotURLChanged(KileDocument::Info*, const QUrl &url)
161 {
162     urlChanged(url);
163 }
164 
operator <(const QTreeWidgetItem & other) const165 bool ProjectViewItem::operator<(const QTreeWidgetItem& other) const
166 {
167     try {
168         const ProjectViewItem& otherItem = dynamic_cast<const ProjectViewItem&>(other);
169 
170         // order in the tree:
171         // - first, root items without container (sorted in ascending order)
172         // - then, container items in fixed order (images, packages, other, projectfile)
173         if(otherItem.type() == KileType::Folder) {
174             if(type() != KileType::Folder) {
175                 return true;
176             }
177             else {
178                 // 'm_folder' is set to a type from 'KileProject::Type'
179                 // we want: Image < Package < Other < ProjectFile
180                 switch(m_folder) {
181                 case KileProjectItem::Image:
182                     return true;
183 
184                 case KileProjectItem::Package:
185                     return (otherItem.m_folder == KileProjectItem::Image) ? false : true;
186 
187                 case KileProjectItem::Other:
188                     return (otherItem.m_folder == KileProjectItem::Image
189                             || otherItem.m_folder == KileProjectItem::Package) ? false : true;
190 
191                 case KileProjectItem::ProjectFile:
192                     return false;
193 
194                 default: // dummy
195                     return false;
196                 }
197             }
198         }
199         else if(type() == KileType::Folder) {
200             return false;
201         }
202         else {
203             return QTreeWidgetItem::operator<(other);
204         }
205     }
206     catch(std::bad_cast&) {
207         return QTreeWidgetItem::operator<(other);
208     }
209 }
210 
setURL(const QUrl & url)211 void ProjectViewItem::setURL(const QUrl &url)
212 {
213     m_url = url;
214 }
215 
url()216 const QUrl &ProjectViewItem::url()
217 {
218     return m_url;
219 }
220 
setArchiveState(bool ar)221 void ProjectViewItem::setArchiveState(bool ar)
222 {
223     setText(1, ar ? "*" : "");
224 }
225 
setFolder(int folder)226 void ProjectViewItem::setFolder(int folder)
227 {
228     m_folder = folder;
229 }
230 
folder() const231 int ProjectViewItem::folder() const
232 {
233     return m_folder;
234 }
235 
236 /*
237  * ProjectView
238  */
ProjectView(QWidget * parent,KileInfo * ki)239 ProjectView::ProjectView(QWidget *parent, KileInfo *ki) : QTreeWidget(parent), m_ki(ki), m_nProjects(0)
240 {
241     setColumnCount(2);
242     QStringList labelList;
243     labelList << i18n("Files & Projects") << i18n("Include in Archive");
244     setHeaderLabels(labelList);
245     setColumnWidth(1, 10);
246 
247     setFocusPolicy(Qt::ClickFocus);
248     header()->hide();
249     header()->setSectionResizeMode(QHeaderView::ResizeToContents);
250     setRootIsDecorated(true);
251     setAllColumnsShowFocus(true);
252     setSelectionMode(QTreeWidget::SingleSelection);
253 
254     connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotClicked(QTreeWidgetItem*)));
255     setAcceptDrops(true);
256 }
257 
slotClicked(QTreeWidgetItem * item)258 void ProjectView::slotClicked(QTreeWidgetItem *item)
259 {
260     if(!item) {
261         item = currentItem();
262     }
263 
264     ProjectViewItem *itm = static_cast<ProjectViewItem*>(item);
265     if(itm) {
266         if(itm->type() == KileType::File) {
267             emit(fileSelected(itm->url()));
268         }
269         else if(itm->type() == KileType::ProjectItem) {
270             emit(fileSelected(itm->projectItem()));
271         }
272         else if(itm->type() != KileType::Folder) {
273             // don't open project configuration files (*.kilepr)
274             if(itm->url().toLocalFile().right(7) != ".kilepr") {
275                 //determine mimeType and open file with preferred application
276                 QMimeDatabase db;
277                 QMimeType pMime = db.mimeTypeForUrl(itm->url());
278                 if(pMime.name().startsWith(QLatin1String("text/"))) {
279                     emit(fileSelected(itm->url()));
280                 }
281                 else {
282                     KRun::runUrl(itm->url(), pMime.name(), this, KRun::RunFlags());
283                 }
284             }
285         }
286         clearSelection();
287     }
288 }
289 
slotFile(int id)290 void ProjectView::slotFile(int id)
291 {
292     ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(currentItem());
293     if(item) {
294         if(item->type() == KileType::File) {
295             switch(id) {
296             case KPV_ID_OPEN:
297                 emit(fileSelected(item->url()));
298                 break;
299             case KPV_ID_SAVE:
300                 emit(saveURL(item->url()));
301                 break;
302             case KPV_ID_ADD:
303                 emit(addToProject(item->url()));
304                 break;
305             case KPV_ID_CLOSE:
306                 emit(closeURL(item->url()));
307                 return; //don't access "item" later on
308             default:
309                 break;
310             }
311         }
312     }
313 }
314 
slotProjectItem(int id)315 void ProjectView::slotProjectItem(int id)
316 {
317     ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(currentItem());
318     if(item) {
319         if(item->type() == KileType::ProjectItem || item->type() == KileType::ProjectExtra) {
320             switch(id) {
321             case KPV_ID_OPEN:
322                 emit(fileSelected(item->projectItem()));
323                 break;
324             case KPV_ID_SAVE:
325                 emit(saveURL(item->url()));
326                 break;
327             case KPV_ID_REMOVE:
328                 emit(removeFromProject(item->projectItem()));
329                 break;
330             case KPV_ID_INCLUDE :
331                 if(item->text(1) == "*") {
332                     item->setText(1, "");
333                 }
334                 else {
335                     item->setText(1, "*");
336                 }
337                 emit(toggleArchive(item->projectItem()));
338                 break;
339             case KPV_ID_CLOSE:
340                 emit(closeURL(item->url()));
341                 break; //we can access "item" later as it isn't deleted
342             case KPV_ID_OPENWITH:
343                 KRun::displayOpenWithDialog(QList<QUrl>() << item->url(), this);
344                 break;
345             default:
346                 break;
347             }
348         }
349     }
350 }
351 
slotProject(int id)352 void ProjectView::slotProject(int id)
353 {
354     ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(currentItem());
355     if(item) {
356         if(item->type() == KileType::Project) {
357             switch(id) {
358             case KPV_ID_BUILDTREE:
359                 emit(buildProjectTree(item->url()));
360                 break;
361             case KPV_ID_OPTIONS:
362                 emit(projectOptions(item->url()));
363                 break;
364             case KPV_ID_CLOSE:
365                 emit(closeProject(item->url()));
366                 return; //don't access "item" later on
367             case KPV_ID_ARCHIVE:
368                 emit(projectArchive(item->url()));
369                 break;
370             case KPV_ID_ADDFILES:
371                 emit(addFiles(item->url()));
372                 break;
373             case KPV_ID_OPENALLFILES:
374                 emit(openAllFiles(item->url()));
375                 break;
376             default:
377                 break;
378             }
379         }
380     }
381 }
382 
slotRun(int id)383 void ProjectView::slotRun(int id)
384 {
385     ProjectViewItem *itm = dynamic_cast<ProjectViewItem*>(currentItem());
386 
387     if(!itm) {
388         return;
389     }
390 
391     if(id == 0) {
392         KRun::displayOpenWithDialog(QList<QUrl>() << itm->url(), this);
393     }
394     else {
395         KRun::runService(*m_offerList[id-1], QList<QUrl>() << itm->url(), this);
396     }
397 
398     itm->setSelected(false);
399 }
400 
makeTheConnection(ProjectViewItem * item,KileDocument::TextInfo * textInfo)401 void ProjectView::makeTheConnection(ProjectViewItem *item, KileDocument::TextInfo *textInfo)
402 {
403     KILE_DEBUG_MAIN << "\tmakeTheConnection " << item->text(0);
404 
405     if (item->type() == KileType::Project) {
406         KileProject *project = m_ki->docManager()->projectFor(item->url());
407         if (!project) {
408             qWarning() << "makeTheConnection COULD NOT FIND AN PROJECT OBJECT FOR " << item->url().toLocalFile();
409         }
410         else {
411             connect(project, SIGNAL(nameChanged(QString)), item, SLOT(nameChanged(QString)));
412         }
413     }
414     else {
415         if(!textInfo) {
416             textInfo = m_ki->docManager()->textInfoFor(item->url().toLocalFile());
417             if(!textInfo) {
418                 KILE_DEBUG_MAIN << "\tmakeTheConnection COULD NOT FIND A DOCINFO";
419                 return;
420             }
421         }
422         item->setInfo(textInfo);
423         connect(textInfo, SIGNAL(urlChanged(KileDocument::Info*,QUrl)),  item, SLOT(slotURLChanged(KileDocument::Info*,QUrl)));
424         connect(textInfo, SIGNAL(isrootChanged(bool)), item, SLOT(isrootChanged(bool)));
425         //set the pixmap
426         item->isrootChanged(textInfo->isLaTeXRoot());
427     }
428 }
429 
folder(const KileProjectItem * pi,ProjectViewItem * item)430 ProjectViewItem* ProjectView::folder(const KileProjectItem *pi, ProjectViewItem *item)
431 {
432     ProjectViewItem *parent = parentFor(pi, item);
433 
434     if(!parent) {
435         qCritical() << "no parent for " << pi->url().toLocalFile();
436         return Q_NULLPTR;
437     }
438 
439     // we have already found the parent folder
440     if(parent->type() == KileType::Folder) {
441         return parent;
442     }
443 
444     // we are looking at the children, if there is an existing folder for this type
445     ProjectViewItem *folder;
446 
447     // determine the foldername for this type
448     QString foldername;
449     switch(pi->type()) {
450     case (KileProjectItem::ProjectFile):
451         foldername = i18n("Project File");
452         break;
453     case (KileProjectItem::Package):
454         foldername = i18n("Packages");
455         break;
456     case (KileProjectItem::Image):
457         foldername = i18n("Images");
458         break;
459     case (KileProjectItem::Bibliography):
460         foldername = i18n("Bibliography");
461         break;
462     case (KileProjectItem::Other):
463     default :
464         foldername = i18n("Other");
465         break;
466     }
467 
468     // if there already a folder for this type on this level?
469     bool found = false;
470     QTreeWidgetItemIterator it(parent);
471     ++it; // skip 'parent'
472     while(*it) {
473         folder = dynamic_cast<ProjectViewItem*>(*it);
474         if(folder && folder->text(0) == foldername) {
475             found = true;
476             break;
477         }
478         ++it;
479     }
480 
481     // if no folder was found, we must create a new one
482     if(!found) {
483         folder = new ProjectViewItem(parent, foldername);
484         KILE_DEBUG_MAIN << "new folder: parent=" << parent->url().url()
485                         << ", foldername=" << foldername;
486 
487         folder->setFolder(pi->type());
488         folder->setType(KileType::Folder);
489     }
490 
491     return folder;
492 }
493 
add(const KileProject * project)494 void ProjectView::add(const KileProject *project)
495 {
496     ProjectViewItem *parent = new ProjectViewItem(this, project);
497 
498     parent->setType(KileType::Project);
499     parent->setURL(project->url());
500     parent->setExpanded(true);
501     parent->setIcon(0, QIcon::fromTheme("relation"));
502     makeTheConnection(parent);
503 
504     //ProjectViewItem *nonsrc = new ProjectViewItem(parent, i18n("non-source"));
505     //parent->setNonSrc(nonsrc);
506 
507     refreshProjectTree(project);
508 
509     ++m_nProjects;
510 }
511 
projectViewItemFor(const QUrl & url)512 ProjectViewItem* ProjectView::projectViewItemFor(const QUrl &url)
513 {
514     ProjectViewItem *item = Q_NULLPTR;
515 
516     //find project view item
517     QTreeWidgetItemIterator it(this);
518     while(*it) {
519         item = dynamic_cast<ProjectViewItem*>(*it);
520         if(item && (item->type() == KileType::Project) && (item->url() == url)) {
521             break;
522         }
523         ++it;
524     }
525 
526     return item;
527 }
528 
itemFor(const QUrl & url)529 ProjectViewItem* ProjectView::itemFor(const QUrl &url)
530 {
531     ProjectViewItem *item = Q_NULLPTR;
532 
533     QTreeWidgetItemIterator it(this);
534     while(*it) {
535         item = static_cast<ProjectViewItem*>(*it);
536         if (item->url() == url) {
537             break;
538         }
539         ++it;
540     }
541 
542     return item;
543 }
544 
parentFor(const KileProjectItem * projitem,ProjectViewItem * projvi)545 ProjectViewItem* ProjectView::parentFor(const KileProjectItem *projitem, ProjectViewItem *projvi)
546 {
547     //find parent projectviewitem of projitem
548     KileProjectItem *parpi = projitem->parent();
549     ProjectViewItem *parpvi = projvi, *vi;
550 
551     if (parpi) {
552         //find parent viewitem that has an URL parpi->url()
553         QTreeWidgetItemIterator it(projvi);
554         KILE_DEBUG_MAIN << "\tlooking for " << parpi->url().toLocalFile();
555         while(*it) {
556             vi = static_cast<ProjectViewItem*>(*it);
557             KILE_DEBUG_MAIN << "\t\t" << vi->url().toLocalFile();
558             if (vi->url() == parpi->url()) {
559                 parpvi = vi;
560                 KILE_DEBUG_MAIN << "\t\tfound" <<endl;
561                 break;
562             }
563             ++it;
564         }
565 
566         KILE_DEBUG_MAIN << "\t\tnot found";
567     }
568     else {
569         KILE_DEBUG_MAIN << "\tlooking for folder type " << projitem->type();
570         QTreeWidgetItemIterator it(projvi);
571         ++it; // skip projvi
572         while(*it) {
573             ProjectViewItem *child = dynamic_cast<ProjectViewItem*>(*it);
574             if(child && (child->type() == KileType::Folder) && (child->folder() == projitem->type())) {
575                 KILE_DEBUG_MAIN << "\t\tfound";
576                 parpvi = child;
577                 break;
578             }
579             ++it;
580         }
581     }
582 
583     return (!parpvi) ? projvi : parpvi;
584 }
585 
add(KileProjectItem * projitem,ProjectViewItem * projvi)586 ProjectViewItem* ProjectView::add(KileProjectItem *projitem, ProjectViewItem *projvi /* = Q_NULLPTR */)
587 {
588     KILE_DEBUG_MAIN << "\tprojectitem=" << projitem->path()
589                     << " projvi=" << projvi;
590     const KileProject *project = projitem->project();
591 
592     if (!projvi) {
593         projvi = projectViewItemFor(project->url());
594     }
595 
596     KILE_DEBUG_MAIN << "\tparent projectviewitem " << projvi->url().fileName();
597 
598     ProjectViewItem *item = Q_NULLPTR, *parent = Q_NULLPTR;
599 
600     switch (projitem->type()) {
601     case (KileProjectItem::Source):
602         item = new ProjectViewItem(projvi, projitem);
603         item->setType(KileType::ProjectItem);
604         item->setIcon(0, QIcon::fromTheme("projectitem"));
605         break;
606     case (KileProjectItem::Package):
607         parent = folder(projitem, projvi);
608         item = new ProjectViewItem(parent, projitem);
609         item->setType(KileType::ProjectItem);
610         item->setIcon(0, QIcon::fromTheme("projectitem"));
611         break;
612     default:
613         parent = folder(projitem, projvi);
614         item = new ProjectViewItem(parent, projitem);
615         item->setType(KileType::ProjectExtra);
616         if(projitem->type() == KileProjectItem::ProjectFile) {
617             item->setIcon(0, QIcon::fromTheme("kile"));
618         }
619         else if(projitem->type() == KileProjectItem::Bibliography) {
620             item->setIcon(0, QIcon::fromTheme("viewbib"));
621         }
622         else {
623             item->setIcon(0, QIcon::fromTheme("file"));
624         }
625         break;
626     }
627 
628     item->setArchiveState(projitem->archive());
629     item->setURL(projitem->url());
630     makeTheConnection(item, projitem->getInfo());
631 
632     projvi->sortChildren(0, Qt::AscendingOrder);
633     // seems to be necessary to get a correct refreh (Qt 4.4.3)
634     bool expanded = projvi->isExpanded();
635     projvi->setExpanded(!expanded);
636     projvi->setExpanded(expanded);
637 
638     return item;
639 }
640 
addTree(KileProjectItem * projitem,ProjectViewItem * projvi)641 void ProjectView::addTree(KileProjectItem *projitem, ProjectViewItem *projvi)
642 {
643     KILE_DEBUG_MAIN << "projitem=" << projitem
644                     << "projvi=" << projvi;
645     ProjectViewItem * item = add(projitem, projvi);
646 
647     if(projitem->firstChild()) {
648         addTree(projitem->firstChild(), item);
649     }
650 
651     if (projitem->sibling()) {
652         addTree(projitem->sibling(), projvi);
653     }
654 }
655 
refreshProjectTree(const KileProject * project)656 void ProjectView::refreshProjectTree(const KileProject *project)
657 {
658     KILE_DEBUG_MAIN << "\tProjectView::refreshProjectTree(" << project->name() << ")";
659     ProjectViewItem *parent= projectViewItemFor(project->url());
660 
661     //clean the tree
662     if(parent) {
663         KILE_DEBUG_MAIN << "\tusing parent projectviewitem " << parent->url().fileName();
664         parent->setFolder(-1);
665         QList<QTreeWidgetItem*> children = parent->takeChildren();
666         for(QList<QTreeWidgetItem*>::iterator it = children.begin();
667                 it != children.end(); ++it) {
668             delete(*it);
669         }
670     }
671     else {
672         return;
673     }
674 
675     //create the non-sources dir
676     //ProjectViewItem *nonsrc = new ProjectViewItem(parent, i18n("non-sources"));
677     //parent->setNonSrc(nonsrc);
678 
679     QList<KileProjectItem*> list = project->rootItems();
680     for(QList<KileProjectItem*>::iterator it = list.begin(); it != list.end(); ++it) {
681         addTree(*it, parent);
682     }
683 
684     parent->sortChildren(0, Qt::AscendingOrder);
685     // seems to be necessary to get a correct refreh (Qt 4.4.3)
686     bool expanded = parent->isExpanded();
687     parent->setExpanded(!expanded);
688     parent->setExpanded(expanded);
689 }
690 
add(const QUrl & url)691 void ProjectView::add(const QUrl &url)
692 {
693     KILE_DEBUG_MAIN << "\tProjectView::adding item " << url.toLocalFile();
694     //check if file is already present
695     QTreeWidgetItemIterator it(this);
696     ProjectViewItem *item;
697     while(*it) {
698         item = static_cast<ProjectViewItem*>(*it);
699         if((item->type() != KileType::Project) && (item->url() == url)) {
700             return;
701         }
702         ++it;
703     }
704 
705     item = new ProjectViewItem(this, url.fileName());
706     item->setType(KileType::File);
707     item->setURL(url);
708     makeTheConnection(item);
709 }
710 
remove(const KileProject * project)711 void ProjectView::remove(const KileProject *project)
712 {
713     for(int i = 0; i < topLevelItemCount(); ++i) {
714         ProjectViewItem *item = static_cast<ProjectViewItem*>(topLevelItem(i));
715 
716         if(item->url() == project->url()) {
717             item->setParent(Q_NULLPTR);
718             delete item;
719             --m_nProjects;
720             break;
721         }
722     }
723 }
724 
725 /**
726  * Removes a file from the projectview, does not remove project-items. Only files without a project.
727  **/
remove(const QUrl & url)728 void ProjectView::remove(const QUrl &url)
729 {
730     for(int i = 0; i < topLevelItemCount(); ++i) {
731         ProjectViewItem *item = dynamic_cast<ProjectViewItem*>(topLevelItem(i));
732 
733         if(item && (item->type() == KileType::File) && (item->url() == url)) {
734             item->setParent(Q_NULLPTR);
735             delete item;
736             break;
737         }
738     }
739 }
740 
removeItem(const KileProjectItem * projitem,bool open)741 void ProjectView::removeItem(const KileProjectItem *projitem, bool open)
742 {
743     QTreeWidgetItemIterator it(this);
744     ProjectViewItem *item;
745     while(*it) {
746         item = dynamic_cast<ProjectViewItem*>(*it);
747         if(item && (item->type() == KileType::ProjectItem) && (item->projectItem() == projitem)) {
748             KILE_DEBUG_MAIN << "removing projectviewitem";
749             static_cast<QTreeWidgetItem*>(item->parent())->removeChild(item);
750             delete item;
751         }
752         ++it;
753     }
754 
755     if(open) {
756         item = new ProjectViewItem(this, projitem->url().fileName());
757         item->setType(KileType::File);
758         item->setURL(projitem->url());
759         makeTheConnection(item);
760     }
761 
762 }
763 
contextMenuEvent(QContextMenuEvent * event)764 void ProjectView::contextMenuEvent(QContextMenuEvent *event)
765 {
766     QMenu popup;
767     QAction *action = Q_NULLPTR;
768 
769     QTreeWidgetItem* treeWidgetItem = itemAt(event->pos());
770     if(!treeWidgetItem) {
771         return;
772     }
773 
774     ProjectViewItem *projectViewItem = dynamic_cast<ProjectViewItem*>(treeWidgetItem);
775     if(!projectViewItem) {
776         return;
777     }
778 
779     if(projectViewItem->type() == KileType::Folder) {
780         return;
781     }
782 
783     bool insertsep = false;
784     bool isKilePrFile = false;
785     if(projectViewItem->type() != KileType::Project && projectViewItem->projectItem()
786             && projectViewItem->projectItem()->project()) {
787         isKilePrFile = projectViewItem->projectItem()->project()->url() == projectViewItem->url();
788     }
789 
790     if(projectViewItem->type() == KileType::ProjectExtra && !isKilePrFile) {
791         QMenu *servicesMenu = popup.addMenu(QIcon::fromTheme("fork"), i18n("&Open With"));
792         QMimeDatabase db;
793         m_offerList = KMimeTypeTrader::self()->query(db.mimeTypeForUrl(projectViewItem->url()).name(), "Application");
794         for (int i = 0; i < m_offerList.count(); ++i) {
795             action = new QAction(servicesMenu);
796             action->setIcon(QIcon::fromTheme(m_offerList[i]->icon()));
797             action->setText(m_offerList[i]->name());
798             connect(action, &QAction::triggered, this, [this, i] { slotRun(i + 1); });
799             servicesMenu->addAction(action);
800         }
801 
802         servicesMenu->addSeparator();
803         servicesMenu->addAction(i18n("Other..."), this, [this] { slotRun(0); });
804         insertsep = true;
805     }
806 
807     if (projectViewItem->type() == KileType::File || projectViewItem->type() == KileType::ProjectItem) {
808         if(!m_ki->isOpen(projectViewItem->url())) {
809             popup.addAction(QIcon::fromTheme("document-open"), i18n("&Open"), this, [this] { slotProjectItem(KPV_ID_OPEN); });
810         }
811         else {
812             popup.addAction(QIcon::fromTheme("document-save"), i18n("&Save"), this, [this] { slotProjectItem(KPV_ID_SAVE); });
813         }
814         insertsep = true;
815     }
816 
817     if(projectViewItem->type() == KileType::File) {
818         if(m_nProjects > 0) {
819             if(insertsep) {
820                 popup.addSeparator();
821             }
822             popup.addAction(QIcon::fromTheme("project_add"), i18n("&Add to Project"), this, [this] { slotProjectItem(KPV_ID_ADD); });
823             insertsep = true;
824         }
825     }
826     else if(projectViewItem->type() == KileType::ProjectItem || projectViewItem->type() == KileType::ProjectExtra) {
827         KileProjectItem *pi = projectViewItem->projectItem();
828         if(pi) {
829             if(insertsep) {
830                 popup.addSeparator();
831             }
832             action = popup.addAction(i18n("&Include in Archive"), this, [this] { slotProjectItem(KPV_ID_INCLUDE); });
833             action->setCheckable(true);
834             action->setChecked(pi->archive());
835             insertsep = true;
836         }
837         if(!isKilePrFile) {
838             if(insertsep) {
839                 popup.addSeparator();
840             }
841             popup.addAction(QIcon::fromTheme("project_remove"),i18n("&Remove From Project"), this, [this] { slotProjectItem(KPV_ID_REMOVE); });
842             insertsep = true;
843         }
844     }
845     else if(projectViewItem->type() == KileType::Project) {
846         if(insertsep) {
847             popup.addSeparator();
848         }
849         popup.addAction(i18n("A&dd Files..."), this, [this] { slotProject(KPV_ID_ADDFILES); });
850         popup.addSeparator();
851         popup.addAction(i18n("Open All &Project Files"), this, [this] { slotProject(KPV_ID_OPENALLFILES); });
852         popup.addSeparator();
853         popup.addAction(QIcon::fromTheme("view-refresh"),i18n("Refresh Project &Tree"), this, [this] { slotProject(KPV_ID_BUILDTREE); });
854         popup.addAction(QIcon::fromTheme("configure"), i18n("Project &Options"), this, [this] { slotProject(KPV_ID_OPTIONS); });
855         popup.addAction(i18n("&Archive"), this, [this] { slotProject(KPV_ID_ARCHIVE); });
856         insertsep = true;
857     }
858 
859     if((projectViewItem->type() == KileType::File) || (projectViewItem->type() == KileType::ProjectItem)
860             || (projectViewItem->type()== KileType::Project)) {
861         if(insertsep) {
862             popup.addSeparator();
863         }
864         if(projectViewItem->type() == KileType::Project) {
865             popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), this, [this] { slotProject(KPV_ID_CLOSE); });
866         }
867         else {
868             popup.addAction(QIcon::fromTheme("view-close"), i18n("&Close"), this, [this] { slotProjectItem(KPV_ID_CLOSE); });
869         }
870     }
871 
872     popup.exec(event->globalPos());
873     m_offerList.clear();
874 }
875 
dragEnterEvent(QDragEnterEvent * event)876 void ProjectView::dragEnterEvent(QDragEnterEvent *event)
877 {
878     if(event->mimeData()->hasUrls()) { // only accept URL drags
879         event->acceptProposedAction();
880     }
881 }
882 
dragMoveEvent(QDragMoveEvent * event)883 void ProjectView::dragMoveEvent(QDragMoveEvent *event)
884 {
885     if(event->mimeData()->hasUrls()) { // only accept URL drags
886         event->acceptProposedAction();
887     }
888 }
889 
dropEvent(QDropEvent * event)890 void ProjectView::dropEvent(QDropEvent *event)
891 {
892     m_ki->docManager()->openDroppedURLs(event);
893 }
894 
895 }
896 
897