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