#include "projectfilesystemwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QFileInfo projectfs_menu_target; enum ItemType { itProject = 1, itFile, itDir }; const int roleFullPath = Qt::UserRole; const int roleItemType = Qt::UserRole + 1; const int roleIsDir = Qt::UserRole + 2; const int roleProject = Qt::UserRole + 3; QAction * newSeparator() { QAction * sep = new QAction(); sep->setSeparator(true); return sep; } ProjectFilesystemWidget::ProjectFilesystemWidget(QWidget * parent): QWidget(parent) { setupUi(this); item_target = nullptr; in_proc = need_rebuild = false; int is = style()->pixelMetric(QStyle::PM_ButtonIconSize, 0, this); label->setFixedSize(is, is); buttonClear->setIcon(Utils::Icons::CLEAN.icon()); buttonExpand->setIcon(Utils::Icons::EXPAND.icon()); buttonCollapse->setIcon(Utils::Icons::COLLAPSE.icon()); actionOpen_here->setIcon(Utils::Icons::OPENFILE.icon()); actionOpen_external->setIcon(Utils::Icons::OPENFILE.icon()); actionShow_external->setIcon(Core::FileIconProvider::icon(QFileIconProvider::Folder)); actionCopy_name->setIcon(Utils::Icons::COPY.icon()); actionCopy_path->setIcon(Utils::Icons::COPY.icon()); actionBuild->setIcon(ProjectExplorer::Icons::BUILD_SMALL.icon()); actionClean->setIcon(Utils::Icons::CLEAN.icon()); actionRun->setIcon(ProjectExplorer::Icons::RUN_FLAT.icon()); actionClose_project->setIcon(Utils::Icons::CLOSE_TOOLBAR.icon()); this_actions << actionSet_as_startup << actionBuild << actionRun; this_actions << newSeparator(); this_actions << actionRebuild << actionClean; this_actions << newSeparator(); this_actions << actionClose_project; this_actions << newSeparator(); this_actions << actionOpen_here << actionOpen_external << actionShow_external << actionOpen_terminal; this_actions << newSeparator(); this_actions << actionCopy_name << actionCopy_path; proj_plug = 0; //connect(ProjectExplorer::ProjectTree::instance(), SIGNAL(subtreeChanged(ProjectExplorer::FolderNode*)), this, SLOT(projectsChanged())); connect(ProjectExplorer::SessionManager::instance(), SIGNAL(startupProjectChanged(ProjectExplorer::Project *)), this, SLOT(startupProjectChanged())); connect(ProjectExplorer::SessionManager::instance(), SIGNAL(projectAdded(ProjectExplorer::Project*)), this, SLOT(projectsChanged())); connect(ProjectExplorer::SessionManager::instance(), SIGNAL(projectDisplayNameChanged(ProjectExplorer::Project*)), this, SLOT(projectsChanged())); connect(ProjectExplorer::SessionManager::instance(), SIGNAL(projectRemoved(ProjectExplorer::Project*)), this, SLOT(projectsChanged())); //connect(ProjectExplorer::SessionManager::instance(), SIGNAL(), this, SLOT(startupProjectChanged())); connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)), this, SLOT(currentFileChanged())); connect(&fs_watcher, SIGNAL(directoryChanged(const QString &)), this, SLOT(directoryChanged(const QString &))); projectsChanged(); } void ProjectFilesystemWidget::setCurrentFilter(const FilterDialog::Filter & v) { cur_filter = v; projectsChanged(); } void ProjectFilesystemWidget::changeEvent(QEvent *e) { QWidget::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: retranslateUi(this); break; default: break; } } void ProjectFilesystemWidget::createTree(QTreeWidgetItem * ti, const QString & dir) { if (ti->childCount() > 0) { qDeleteAll(ti->takeChildren()); } QFileInfoList fl = QDir(dir).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::LocaleAware | QDir::DirsFirst); checkProcEvents(); fs_watcher.addPath(dir); item_map[dir] = ti; for (QFileInfo i: fl) { QString nit = i.fileName(); if (i.isDir()) { if (!cur_filter.filterDir(nit)) continue; } else { if (!cur_filter.filterFile(nit)) continue; } QTreeWidgetItem * ni = new QTreeWidgetItem(); ni->setText(0, nit); ni->setIcon(0, Core::FileIconProvider::icon(i)); ni->setData(0, roleFullPath, i.absoluteFilePath()); ni->setData(0, roleItemType, i.isDir() ? itDir : itFile); ni->setData(0, roleIsDir, i.isDir()); item_map[i.absoluteFilePath()] = ni; if (i.isDir()) { createTree(ni, dir + "/" + i.fileName()); } ti->addChild(ni); } //if (ti->childCount() == 0) delete ti; } bool ProjectFilesystemWidget::filterTree(QTreeWidgetItem * ti, const QString & filter) { bool ret = false; for (int i = 0; i < ti->childCount(); ++i) { QTreeWidgetItem * ci = ti->child(i); QString cit = ci->text(0); if (ci->data(0, roleIsDir).toBool()) { if (!filterTree(ci, filter)) { ci->setHidden(true); continue; } ci->setHidden(false); ret = true; } else { bool f = false; if (filter.isEmpty()) { f = true; } else { f = f || cit.contains(filter); } ci->setHidden(!f); if (f) ret = true; } } return ret; } void ProjectFilesystemWidget::filter() { QString f = lineFilter->text(); for (int i = 0; i < tree->topLevelItemCount(); ++i) { QTreeWidgetItem * ti = tree->topLevelItem(i); filterTree(ti, f); } } void ProjectFilesystemWidget::rememberExpanded(QTreeWidgetItem * ti) { //QMessageBox::information(0, ti->data(0, roleFullPath).toString(), QString::number(ti->childCount())); for (int i = 0; i < ti->childCount(); ++i) { QTreeWidgetItem * ci = ti->child(i); if (ci->data(0, roleIsDir).toBool()) { if (ci->isExpanded()) last_expanded << ci->data(0, roleFullPath).toString(); rememberExpanded(ci); } } } void ProjectFilesystemWidget::restoreExpanded(QTreeWidgetItem * ti) { for (int i = 0; i < ti->childCount(); ++i) { QTreeWidgetItem * ci = ti->child(i); if (ci->data(0, roleIsDir).toBool()) { if (last_expanded.contains(ci->data(0, roleFullPath).toString())) ci->setExpanded(true); restoreExpanded(ci); } } } void ProjectFilesystemWidget::setExtVariable() { } void ProjectFilesystemWidget::checkProcEvents() { if (tm.elapsed() < 10) return; QApplication::processEvents(); tm.start(); } void * ProjectFilesystemWidget::itemProject(QTreeWidgetItem * ti) { if (!ti) return nullptr; return (void*)(ti->data(0, roleProject).toULongLong()); } void ProjectFilesystemWidget::projectsChanged() { if (in_proc) { need_rebuild = true; return; } in_proc = true; tm.start(); last_expanded.clear(); item_map.clear(); int spos = tree->verticalScrollBar()->value(); rememberExpanded(tree->invisibleRootItem()); tree->clear(); fs_watcher.removePaths(fs_watcher.directories()); QApplication::setOverrideCursor(Qt::WaitCursor); QList pl = ProjectExplorer::SessionManager::projects(); for (ProjectExplorer::Project * p: pl) { QTreeWidgetItem * ri = new QTreeWidgetItem(); QString dir = p->projectDirectory().toString(); ri->setText(0, p->displayName()); QFile logo(dir + "/logo.png"); if (logo.exists()) ri->setIcon(0, QIcon(logo.fileName())); else ri->setIcon(0, Core::FileIconProvider::icon(QFileIconProvider::Folder)); ri->setData(0, roleProject, (qulonglong)p); ri->setData(0, roleFullPath, dir); ri->setData(0, roleIsDir, true); ri->setData(0, roleItemType, itProject); createTree(ri, dir); tree->addTopLevelItem(ri); } startupProjectChanged(); currentFileChanged(); filter(); restoreExpanded(tree->invisibleRootItem()); QApplication::restoreOverrideCursor(); qApp->processEvents(); tree->verticalScrollBar()->setValue(spos); in_proc = false; if (need_rebuild) { need_rebuild = false; projectsChanged(); } } void ProjectFilesystemWidget::filterClicked() { filter_dialog.setFilter(cur_filter); if (filter_dialog.exec() == QDialog::Rejected) return; setCurrentFilter(filter_dialog.filter()); } void ProjectFilesystemWidget::currentFileChanged() { Core::IDocument * cd = Core::EditorManager::instance()->currentDocument(); if (!cd) return; QString np = cd->filePath().toString(); QTreeWidgetItem * ti = item_map.value(np); if (!ti) return; tree->setCurrentItem(ti); tree->expandItem(ti); } void ProjectFilesystemWidget::startupProjectChanged() { ProjectExplorer::Project * sp = ProjectExplorer::SessionManager::startupProject(); QFont f(tree->font()), bf(f); bf.setBold(true); for (int i = 0; i < tree->topLevelItemCount(); ++i) { QTreeWidgetItem * ti = tree->topLevelItem(i); ti->setFont(0, f); if (!sp) continue; if (sp->projectDirectory().toString() == ti->data(0, roleFullPath).toString()) ti->setFont(0, bf); } } void ProjectFilesystemWidget::directoryChanged(const QString & path) { QTreeWidgetItem * ti = item_map.value(path); //QMessageBox::information(0, "", "changed " + path + " " + QString::number((qulonglong)ti)); if (!ti) return; int spos = tree->verticalScrollBar()->value(); rememberExpanded(tree->invisibleRootItem()); createTree(ti, path); filter(); restoreExpanded(tree->invisibleRootItem()); QList ail = tree->findItems("", Qt::MatchContains | Qt::MatchRecursive), map_values = item_map.values(); QSet ais; //QString removed; for (auto * i: ail) ais << i; for (auto * i: map_values) if (!ais.contains(i)) { //removed += item_map.key(i) + "\n"; item_map.remove(item_map.key(i)); } //QMessageBox::information(0, "", "map " + QString::number(ais.size())); //QMessageBox::information(0, "", "remove " + removed); } void ProjectFilesystemWidget::on_tree_itemDoubleClicked(QTreeWidgetItem * item, int) { if (!item) return; QString afp = item->data(0, roleFullPath).toString(); bool dir = item->data(0, roleIsDir).toBool(); if (dir) return; if (afp.isEmpty()) return; Core::EditorManager::openEditor(afp); } void ProjectFilesystemWidget::on_lineFilter_textChanged(const QString & ) { filter(); } void ProjectFilesystemWidget::on_tree_itemClicked(QTreeWidgetItem * item, int column) { projectfs_menu_target = QFileInfo(); if (!item) { setExtVariable(); return; } projectfs_menu_target = QFileInfo(item->data(0, roleFullPath).toString()); setExtVariable(); } void ProjectFilesystemWidget::on_tree_customContextMenuRequested(const QPoint & pos) { projectfs_menu_target = QFileInfo(); QTreeWidgetItem * item = tree->itemAt(pos); //QMessageBox::information(this, "", QString::number(index.row())); item_target = nullptr; if (!item) { setExtVariable(); return; } item_target = item; projectfs_menu_target = QFileInfo(item->data(0, roleFullPath).toString()); setExtVariable(); actionOpen_here->setEnabled(!projectfs_menu_target.isDir()); actionOpen_external->setEnabled(!projectfs_menu_target.isDir()); popup_menu.clear(); /*if (item->data(0, roleItemType).toInt() == itProject) { QString proj_path = item->data(0, roleFullPath).toString(); ProjectExplorer::Project * project = Utils::findOrDefault(ProjectExplorer::SessionManager::projects(), [proj_path](const ProjectExplorer::Project * p) {return p->containerNode()->path() == proj_path;}); //ProjectExplorer::ProjectTree::instance()->setCurrent QMenu * contextMenu = Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_PROJECTCONTEXT)->menu(); //contextMenu = Core::ActionManager::actionContainer(Constants::M_FOLDERCONTEXT)->menu(); //contextMenu = Core::ActionManager::actionContainer(Constants::M_FILECONTEXT)->menu(); popup_menu.addActions(contextMenu->actions()); }*/ ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (p) { actionSet_as_startup->setVisible(p != ProjectExplorer::SessionManager::startupProject()); bool can_build = !p->needsConfiguration(), can_run = false; if (p->activeTarget()) { can_build = can_build && p->activeTarget()->activeBuildConfiguration(); can_run = p->activeTarget()->activeRunConfiguration(); } actionBuild->setVisible(can_build); actionClean->setVisible(can_build); actionRebuild->setVisible(can_build); actionRun->setVisible(can_run); } else { actionSet_as_startup->setVisible(false); actionBuild->setVisible(false); actionClean->setVisible(false); actionRebuild->setVisible(false); actionRun->setVisible(false); } actionClose_project->setVisible(p); popup_menu.addActions(this_actions); popup_menu.popup(tree->mapToGlobal(pos)); } void ProjectFilesystemWidget::on_actionOpen_here_triggered() { if (projectfs_menu_target.path().isEmpty()) return; Core::EditorManager::openEditor(projectfs_menu_target.absoluteFilePath(), Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); } void ProjectFilesystemWidget::on_actionOpen_external_triggered() { if (projectfs_menu_target.path().isEmpty()) return; QString wd = QDir::current().absolutePath(); QDir::setCurrent(projectfs_menu_target.absoluteDir().path()); QDesktopServices::openUrl(QUrl::fromLocalFile(projectfs_menu_target.absoluteFilePath())); QDir::setCurrent(wd); } void ProjectFilesystemWidget::on_actionShow_external_triggered() { if (projectfs_menu_target.path().isEmpty()) return; Core::FileUtils::showInGraphicalShell(Core::ICore::mainWindow(), projectfs_menu_target.absoluteFilePath()); } void ProjectFilesystemWidget::on_actionOpen_terminal_triggered() { if (projectfs_menu_target.path().isEmpty()) return; Core::FileUtils::openTerminal(QDir(projectfs_menu_target.absoluteFilePath()).path()); } void ProjectFilesystemWidget::on_actionCopy_name_triggered() { if (projectfs_menu_target.path().isEmpty()) return; QApplication::clipboard()->setText(projectfs_menu_target.fileName()); } void ProjectFilesystemWidget::on_actionCopy_path_triggered() { if (projectfs_menu_target.path().isEmpty()) return; QApplication::clipboard()->setText(projectfs_menu_target.absoluteFilePath()); } void ProjectFilesystemWidget::on_actionSet_as_startup_triggered() { ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (!p) return; ProjectExplorer::SessionManager::setStartupProject(p); } void ProjectFilesystemWidget::on_actionBuild_triggered() { ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (!p) return; ProjectExplorer::BuildManager::buildProjectWithDependencies(p); } void ProjectFilesystemWidget::on_actionRebuild_triggered() { ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (!p) return; ProjectExplorer::BuildManager::rebuildProjectWithDependencies(p, ProjectExplorer::ConfigSelection::Active); } void ProjectFilesystemWidget::on_actionClean_triggered() { ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (!p) return; ProjectExplorer::BuildManager::cleanProjectWithoutDependencies(p); } void ProjectFilesystemWidget::on_actionRun_triggered() { ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (!p) return; ProjectExplorer::ProjectExplorerPlugin::runProject(p, ProjectExplorer::Constants::NORMAL_RUN_MODE); } void ProjectFilesystemWidget::on_actionClose_project_triggered() { ProjectExplorer::Project * p = (ProjectExplorer::Project *)itemProject(item_target); if (!p) return; if (QMessageBox::question(0, "Project close", tr("Are you sure to close project \"%1\"?").arg(p->displayName())) != QMessageBox::Yes) return; ProjectExplorer::SessionManager::removeProject(p); }