summaryrefslogtreecommitdiffstats
path: root/src/libgui/project_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libgui/project_manager.cpp')
-rw-r--r--src/libgui/project_manager.cpp651
1 files changed, 651 insertions, 0 deletions
diff --git a/src/libgui/project_manager.cpp b/src/libgui/project_manager.cpp
new file mode 100644
index 0000000..dcc4941
--- /dev/null
+++ b/src/libgui/project_manager.cpp
@@ -0,0 +1,651 @@
+/***************************************************************************
+ * Copyright (C) 2005-2006 Nicolas Hadacek <hadacek@kde.org> *
+ * Copyright (C) 2003 Alain Gibaud <alain.gibaud@free.fr> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+#include "project_manager.h"
+
+#include <qdragobject.h>
+#include <qpainter.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include <qheader.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kaction.h>
+#include <kapplication.h>
+
+#include "project.h"
+#include "project_wizard.h"
+#include "project_editor.h"
+#include "toplevel.h"
+#include "editor_manager.h"
+#include "object_view.h"
+#include "devices/list/device_list.h"
+#include "tools/list/compile_config.h"
+#include "register_view.h"
+#include "hex_editor.h"
+#include "main_global.h"
+#include "common/gui/purl_gui.h"
+#include "device_gui.h"
+
+//----------------------------------------------------------------------------
+ProjectManager::View::View(QWidget *parent)
+ : ListView(parent, "project_manager"), _project(0), _modified(false)
+{
+ connect(this, SIGNAL(mouseButtonClicked(int, QListViewItem *, const QPoint &, int)),
+ SLOT(clicked(int, QListViewItem *, const QPoint &, int)));
+ connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)),
+ SLOT(contextMenu(QListViewItem *, const QPoint &, int)));
+ connect(this, SIGNAL(itemRenamed(QListViewItem *, int, const QString &)),
+ SLOT(renamed(QListViewItem *, int, const QString &)));
+ connect(this, SIGNAL(moved()), SLOT(filesReordered()));
+
+ header()->hide();
+ setSorting(-1);
+ addColumn(QString::null, 170);
+ setFullWidth(true);
+ setRootIsDecorated(false);
+ setAcceptDrops(true);
+ setDragEnabled(true);
+ setDropVisualizer(true);
+ QTimer::singleShot(0, this, SLOT(init()));;
+}
+
+ProjectManager::View::~View()
+{
+ delete _project;
+}
+
+void ProjectManager::View::init()
+{
+ clear();
+ _rootItem = new RootItem(this);
+ setCurrentItem(_rootItem);
+ KListViewItem *item = new RegisterItem(headerItem(DeviceGroup));
+ ensureItemVisible(item);
+ _deviceItem = new DeviceItem(headerItem(DeviceGroup));
+ ensureItemVisible(_deviceItem);
+ _linkerScriptItem = 0;
+ (void)headerItem(SourceGroup);
+}
+
+ProjectManager::HeaderItem *ProjectManager::View::findHeaderItem(Group group) const
+{
+ QListViewItemIterator it(const_cast<View *>(this));
+ for(; it.current(); ++it) {
+ if ( it.current()->rtti()!=HeaderRtti ) continue;
+ HeaderItem *hi = static_cast<HeaderItem *>(it.current());
+ if ( hi->group()==group ) return hi;
+ }
+ return 0;
+}
+
+ProjectManager::HeaderItem *ProjectManager::View::headerItem(Group group)
+{
+ HeaderItem *item = findHeaderItem(group);
+ if (item) return item;
+ item = new HeaderItem(_rootItem, group);
+ // reorder groups...
+ HeaderItem *items[Nb_Groups];
+ for (uint i=0; i<Nb_Groups; i++) {
+ items[i] = findHeaderItem(Group(i));
+ if (items[i]) _rootItem->takeItem(items[i]);
+ }
+ for (int i=Nb_Groups-1; i>=0; i--) {
+ if ( items[i]==0 ) continue;
+ _rootItem->insertItem(items[i]);
+ }
+ return item;
+}
+
+ProjectManager::FileItem *ProjectManager::View::findFileItem(const PURL::Url &url) const
+{
+ QListViewItemIterator it(const_cast<View *>(this));
+ for(; it.current(); ++it) {
+ if ( it.current()->rtti()!=FileRtti ) continue;
+ FileItem *fi = static_cast<FileItem *>(it.current());
+ if ( fi->url()==url ) return fi;
+ }
+ return 0;
+}
+
+ProjectManager::FileItem *ProjectManager::View::findFileItem(PURL::FileType type) const
+{
+ QListViewItemIterator it(const_cast<View *>(this));
+ for(; it.current(); ++it) {
+ if ( it.current()->rtti()!=FileRtti ) continue;
+ FileItem *fi = static_cast<FileItem *>(it.current());
+ if ( fi->ftype()==type ) return fi;
+ }
+ return 0;
+}
+
+QListViewItem *ProjectManager::View::findItem(const QString &tag) const
+{
+ QListViewItemIterator it(const_cast<View *>(this));
+ for(; it.current(); ++it) {
+ switch (Rtti(it.current()->rtti())) {
+ case RootRtti:
+ case FileRtti:
+ case LinkerScriptRtti:
+ case DeviceRtti: continue;
+ case HeaderRtti:
+ case RegisterRtti: break;
+ }
+ if ( it.current()->text(0)==tag ) return it.current();
+ }
+ return 0;
+}
+
+void ProjectManager::View::select(const Editor *e)
+{
+ QListViewItem *item = 0;
+ if ( e->url().isEmpty() ) item = findItem(e->tag());
+ else item = findFileItem(e->url());
+ if (item) setSelected(item, true);
+ else clearSelection();
+}
+
+void ProjectManager::View::contextMenu(QListViewItem *item, const QPoint &p, int)
+{
+ if ( item==0 ) return;
+
+ PopupMenu pop;
+ Group group = Nb_Groups;
+ if ( item->rtti()==HeaderRtti) group = static_cast<const HeaderItem *>(item)->group();
+
+ if ( item->rtti()==LinkerScriptRtti || group==LinkerScriptGroup ) {
+ if ( _project==0 || Main::toolGroup().linkerScriptType()==PURL::Nb_FileTypes ) return;
+ pop.insertTitle(i18n("Linker Script"));
+ pop.insertItem("piklab_addfile", i18n("Set Custom..."));
+ if ( !_project->customLinkerScript().isEmpty() ) pop.insertItem("editdelete", i18n("Set Default"));
+ switch( pop.exec(p) ) {
+ case 1: {
+ PURL::Url url = PURL::getOpenUrl(":custom_linker_script", PURL::filter(Main::toolGroup().linkerScriptType()), this, i18n("Select Linker Script"));
+ if ( !url.isEmpty() ) _project->setCustomLinkerScript(url);
+ break;
+ }
+ case 2: _project->setCustomLinkerScript(PURL::Url()); break;
+ }
+ _linkerScriptItem->init();
+ } else if ( item->rtti()==RootRtti ) {
+ RootItem *ri = static_cast<RootItem *>(item);
+ if ( _project==0 ) {
+ if ( ri->url().isEmpty() ) {
+ pop.insertItem("piklab_createproject", i18n("New Project..."), &Main::toplevel(), SLOT(newProject()));
+ pop.insertItem("piklab_openproject", i18n("Open Project..."), &Main::toplevel(), SLOT(openProject()));
+ pop.exec(p);
+ } else {
+ pop.insertTitle(i18n("Standalone File"));
+ pop.insertItem("configure", i18n("Configure..."));
+ if ( pop.exec(p)==1 ) Main::toplevel().configure(ConfigCenter::Standalone);
+ }
+ } else {
+ pop.insertTitle(i18n("Project"));
+ pop.insertItem("configure", i18n("Options..."), &Main::toplevel(), SLOT(configureProject()));
+ pop.insertItem("find", i18n("Find Files..."), &Main::toplevel(), SLOT(runKfind()));
+ pop.insertSeparator();
+ pop.insertItem("piklab_compile", i18n("Build Project"), &Main::toplevel(), SLOT(buildProject()));
+ pop.insertItem("trashcan_empty", i18n("Clean Project"), &Main::toplevel(), SLOT(cleanBuild()));
+ pop.insertSeparator();
+ pop.insertItem("filenew", i18n("New Source File..."), &Main::toplevel(), SLOT(newSourceFile()));
+ pop.insertItem("piklab_addfile", i18n("Add Source Files..."), this, SLOT(insertSourceFiles()));
+ pop.insertItem("piklab_addfile", i18n("Add Object Files..."), this, SLOT(insertObjectFiles()));
+ if ( Main::currentEditor() ) pop.insertItem("piklab_addcurrentfile", i18n("Add Current File"), this, SLOT(insertCurrentFile()));
+ pop.exec(p);
+ }
+ } else if ( item->rtti()==FileRtti ) {
+ if ( _project==0 ) return;
+ FileItem *fi = static_cast<FileItem *>(item);
+ if ( isExternalFile(fi->url()) ) return;
+ pop.insertTitle(item->text(0));
+ pop.insertItem("editdelete", i18n("Remove From Project"));
+ if ( pop.exec(p)==1 ) removeFile(fi->url());
+ } else if ( item->rtti()==HeaderRtti ) {
+ if ( _project==0 ) return;
+ if ( group==LinkerObjectGroup ) {
+ pop.insertTitle(i18n("Objects"));
+ pop.insertItem("piklab_addfile", i18n("Add Object Files..."), this, SLOT(insertObjectFiles()));
+ pop.exec(p);
+ } else if ( group==SourceGroup || group==HeaderGroup ) {
+ pop.insertTitle(i18n("Sources"));
+ pop.insertItem("filenew", i18n("New File..."), &Main::toplevel(), SLOT(newSourceFile()));
+ pop.insertItem("piklab_addfile", i18n("Add Source Files..."), this, SLOT(insertSourceFiles()));
+ pop.exec(p);
+ } else if ( group==DeviceGroup ) {
+ pop.insertItem("filenew", i18n("Select Device..."), &Main::toplevel(), SLOT(showDeviceInfo()));
+ pop.exec(p);
+ }
+ }
+}
+
+void ProjectManager::View::closeProject()
+{
+ if ( _project==0 && projectUrl().isEmpty() ) return;
+ if (_project) {
+ // save opened files
+ PURL::UrlList files = Main::editorManager().files();
+ PURL::UrlList::const_iterator it = files.begin();
+ PURL::UrlList opened;
+ for (; it!=files.end(); ++it) {
+ if ( !isExternalFile(*it) ) opened += *it;
+ Main::editorManager().closeEditor(*it);
+ }
+ _project->setOpenedFiles(opened);
+ // save watched registers
+ _project->setWatchedRegisters(Register::list().watched());
+ QString error;
+ if ( !_project->save(error) )
+ MessageBox::detailedSorry(i18n("Could not save project file \"%1\".").arg(_project->url().pretty()), error, Log::Show);
+ delete _project;
+ _project = 0;
+ }
+ _modified = false;
+ init();
+}
+
+void ProjectManager::View::addExternalFiles()
+{
+ const QMap<PURL::Url, FileOrigin> &ext = projectData().externals;
+ QMap<PURL::Url, FileOrigin>::const_iterator it;
+ for (it=ext.begin(); it!=ext.end(); ++it) {
+ if ( !it.key().exists() ) continue;
+ addFile(it.key(), it.key().fileType(), it.data());
+ }
+}
+
+void ProjectManager::View::setStandalone(const PURL::Url &url, PURL::FileType type)
+{
+ if ( projectUrl()==url ) return;
+ closeProject();
+ _rootItem->set(url, true);
+ addFile(url, type, Intrinsic);
+ _standaloneData[url].type = type;
+ addExternalFiles();
+}
+
+PURL::Url ProjectManager::View::standaloneGenerator(const PURL::Url &url, PURL::FileType &type) const
+{
+ QMap<PURL::Url, ProjectData>::const_iterator it;
+ for (it=_standaloneData.begin(); it!=_standaloneData.end(); ++it) {
+ if ( !it.data().externals.contains(url) ) continue;
+ if ( !it.key().exists() ) continue;
+ type = it.data().type;
+ return it.key();
+ }
+ type = PURL::Nb_FileTypes;
+ return url;
+}
+
+void ProjectManager::View::insertSourceFiles()
+{
+ Q_ASSERT(_project);
+ PURL::UrlList list = PURL::getOpenUrls(":<sources>", PURL::sourceFilter(PURL::CompleteFilter), this, i18n("Select Source File"));
+ if ( list.isEmpty() ) return;
+ PURL::UrlList::const_iterator it;
+ for (it=list.begin(); it!=list.end(); ++it) insertFile(*it);
+}
+
+void ProjectManager::View::insertObjectFiles()
+{
+ Q_ASSERT(_project);
+ PURL::UrlList list = PURL::getOpenUrls(":<objects>", PURL::objectFilter(PURL::CompleteFilter), this, i18n("Select Object File"));
+ if ( list.isEmpty() ) return;
+ PURL::UrlList::const_iterator it;
+ for (it=list.begin(); it!=list.end(); ++it) insertFile(*it);
+}
+
+void ProjectManager::View::insertFile(const PURL::Url &url)
+{
+ if ( !url.exists() ) {
+ MessageBox::detailedSorry(i18n("Could not find file."), i18n("File: %1").arg(url.pretty()), Log::Show);
+ return;
+ }
+ PURL::Url purl = url;
+ MessageBox::Result copy = MessageBox::No;
+ if ( !url.isInto(_project->directory()) ) {
+ copy = MessageBox::questionYesNoCancel(i18n("File \"%1\" is not inside the project directory. Do you want to copy the file to your project directory?").arg(url.pretty()),
+ i18n("Copy and Add"), i18n("Add only"));
+ if ( copy==MessageBox::Cancel ) return;
+ if ( copy==MessageBox::Yes ) purl = PURL::Url(_project->directory(), url.filename());
+ }
+ if ( _project->absoluteFiles().contains(purl) ) {
+ MessageBox::detailedSorry(i18n("File is already in the project."), i18n("File: %1").arg(purl.pretty()), Log::Show);
+ return;
+ }
+ if ( copy==MessageBox::Yes ) {
+ Log::StringView sview;
+ if ( !url.copyTo(purl, sview) ) {
+ MessageBox::detailedSorry(i18n("Copying file to project directory failed."), i18n("File: %1\n").arg(url.pretty()) + sview.string(), Log::Show);
+ return;
+ }
+ }
+ _project->addFile(purl);
+ addFile(purl, purl.fileType(), Intrinsic);
+}
+
+bool ProjectManager::View::openProject()
+{
+ PURL::Url url = PURL::getOpenUrl(":open_project", PURL::projectFilter(PURL::CompleteFilter), this, i18n("Select Project file"));
+ return openProject(url);
+}
+
+void ProjectManager::View::addExternalFile(const PURL::Url &url, FileOrigin origin)
+{
+ Q_ASSERT( origin!=Intrinsic );
+ addFile(url, url.fileType(), origin);
+}
+
+const ProjectManager::View::ProjectData &ProjectManager::View::projectData() const
+{
+ if ( _project==0 ) return _standaloneData[projectUrl()];
+ return _projectData;
+}
+
+ProjectManager::View::ProjectData &ProjectManager::View::projectData()
+{
+ if ( _project==0 ) return _standaloneData[projectUrl()];
+ return _projectData;
+}
+
+void ProjectManager::View::addFile(const PURL::Url &url, PURL::FileType type, FileOrigin origin)
+{
+ if ( contains(url) ) return;
+ QMap<PURL::Url, FileOrigin> &ext = projectData().externals;
+ if ( type.data().group==PURL::LinkerScript && _linkerScriptItem ) {
+ _linkerScriptItem->set(url);
+ ext[url] = Included;
+ return;
+ }
+ PURL::FileProperties properties = type.data().properties;
+ Group grp = Nb_Groups;
+ switch (origin) {
+ case Intrinsic: grp = group(type); break;
+ case Generated: grp = GeneratedGroup; break;
+ case Included: grp = IncludedGroup; break;
+ }
+ HeaderItem *hitem = headerItem(grp);
+ QListViewItem *item = new FileItem(hitem, type, url, origin!=Intrinsic);
+ item->moveItem(hitem->lastChild());
+ ensureItemVisible(item);
+ if ( origin!=Intrinsic ) ext[url] = origin;
+ if ( type==PURL::Hex && _project==0 ) {
+ QString extension = PURL::extension(PURL::AsmGPAsm);
+ PURL::Url durl = PURL::Url::fromPathOrUrl("<" + (url.isEmpty() ? i18n("Disassembly") : url.appendExtension(extension).filename()) + ">");
+ if ( findFileItem(durl)==0 ) {
+ (void)new FileItem(headerItem(ViewGroup), PURL::Coff, durl, true);
+ ext[durl] = Generated;
+ }
+ }
+ if ( _project && origin==Intrinsic ) _modified = true;
+}
+
+void ProjectManager::View::removeExternalFiles()
+{
+ QMap<PURL::Url, FileOrigin> &ext = projectData().externals;
+ QMap<PURL::Url, FileOrigin>::const_iterator it;
+ for (it=ext.begin(); it!=ext.end(); ++it) {
+ Main::editorManager().closeEditor(it.key());
+ removeFile(it.key());
+ }
+ ext.clear();
+ if (_linkerScriptItem) _linkerScriptItem->init();
+}
+
+void ProjectManager::View::removeFile(const PURL::Url &url)
+{
+ if ( _project && !isExternalFile(url) ) _project->removeFile(url);
+ FileItem *item = findFileItem(url);
+ if ( item==0 ) return;
+ HeaderItem *group = static_cast<HeaderItem *>(item->parent());
+ delete item;
+ if ( group->childCount()==0 ) delete group;
+ _modified = true;
+ emit guiChanged();
+}
+
+void ProjectManager::View::clicked(int button, QListViewItem *item, const QPoint &, int)
+{
+ if ( item==0 ) return;
+ if ( button!=LeftButton ) return;
+ const Device::Data *data = Main::deviceData();
+ Rtti rtti = Rtti(item->rtti());
+ if ( data==0 && rtti!=DeviceRtti && rtti!=RootRtti ) {
+ MessageBox::sorry(i18n("Cannot open without device specified."), Log::Show);
+ return;
+ }
+ Editor *e = 0;
+ ::BusyCursor bc;
+ switch (rtti) {
+ case RootRtti:
+ Main::toplevel().configureProject();
+ break;
+ case HeaderRtti: {
+ if ( static_cast<HeaderItem *>(item)->group()!=DeviceGroup ) break;
+ e = Main::editorManager().openEditor(EditorManager::DeviceEditor);
+ break;
+ }
+ case RegisterRtti:
+ e = Main::editorManager().openEditor(EditorManager::RegisterEditor);
+ break;
+ case DeviceRtti: return;
+ case LinkerScriptRtti: {
+ PURL::Url url = Main::projectManager().linkerScriptUrl();
+ if ( url.isEmpty() ) break;
+ e = Main::editorManager().findEditor(url);
+ if ( e==0 ) {
+ e = Main::editorManager().createEditor(url.fileType(), url);
+ if ( !e->open(url) ) {
+ delete e;
+ break;
+ }
+ if ( e && isExternalFile(url) ) e->setReadOnly(true);
+ Main::editorManager().addEditor(e);
+ } else Main::editorManager().showEditor(e);
+ break;
+ }
+ case FileRtti: {
+ FileItem *fi = static_cast<FileItem *>(item);
+ if ( !(fi->ftype().data().properties & PURL::Editable) ) break;
+ e = Main::editorManager().findEditor(fi->url());
+ if ( e==0 ) {
+ if ( fi->ftype()==PURL::Coff && _project==0 && !fi->url().exists() ) {
+ PURL::Url url = findFileItem(PURL::Hex)->url();
+ if ( url.isEmpty() ) {
+ HexEditor *he = ::qt_cast<HexEditor *>(Main::currentEditor());
+ if ( he==0 ) break;
+ e = new DisassemblyEditor(*he, *data, this);
+ } else e = new DisassemblyEditor(url, *data, this);
+ addExternalFile(fi->url(), Generated);
+ } else e = Main::editorManager().createEditor(fi->url().fileType(), fi->url());
+ if ( e==0 ) break;
+ if ( !e->open(fi->url()) ) {
+ delete e;
+ break;
+ }
+ if ( isExternalFile(fi->url()) ) e->setReadOnly(true);
+ Main::editorManager().addEditor(e);
+ } else Main::editorManager().showEditor(e);
+ break;
+ }
+ }
+ cancelRenaming();
+ emit guiChanged();
+}
+
+void ProjectManager::View::insertCurrentFile()
+{
+ insertFile(Main::editorManager().currentEditor()->url());
+}
+
+bool ProjectManager::View::editProject()
+{
+ ProjectEditor dialog(*_project, this);
+ if ( dialog.exec()!=QDialog::Accepted ) return false;
+ _modified = true;
+ if (_linkerScriptItem) _linkerScriptItem->init();
+ return true;
+}
+
+bool ProjectManager::View::newProject()
+{
+ ProjectWizard wizard(this);
+ if ( wizard.exec()==QDialog::Rejected ) return false;
+ closeProject();
+ QString error;
+ if ( !wizard.project()->save(error) ) {
+ MessageBox::detailedSorry(i18n("Failed to create new project file"), error, Log::Show);
+ return false;
+ }
+ openProject(wizard.url());
+ return true;
+}
+
+void ProjectManager::View::setProject(Project *project)
+{
+ closeProject();
+ Main::editorManager().closeAllEditors();
+ _project = project;
+ _rootItem->set(project->url(), false);
+ if ( project && Main::toolGroup().linkerScriptType()!=PURL::Nb_FileTypes ) {
+ _linkerScriptItem = new LinkerScriptItem(headerItem(LinkerScriptGroup));
+ ensureItemVisible(_linkerScriptItem);
+ }
+}
+
+bool ProjectManager::View::openProject(const PURL::Url &url)
+{
+ if ( url.isEmpty() ) return false;
+ bool reload = ( _project && _project->url()==url );
+ if ( reload && !MessageBox::askContinue(i18n("Project already loaded. Reload?"), i18n("Reload")) ) return false;
+ static_cast< KRecentFilesAction *>(Main::action("project_open_recent"))->removeURL(url.kurl());
+ Project *p = new Project(url);
+ QString error;
+ if ( !p->load(error) ) {
+ MessageBox::detailedSorry(i18n("Could not open project file."), error, Log::Show);
+ delete p;
+ return false;
+ }
+ setProject(p);
+ PURL::UrlList files = _project->absoluteFiles();
+ PURL::UrlList::const_iterator it;
+ for(it=files.begin(); it!=files.end(); ++it) addFile(*it, (*it).fileType(), Intrinsic);
+ _projectData.type = PURL::Project;
+ _projectData.externals.clear();
+ static_cast<KRecentFilesAction *>(Main::action("project_open_recent"))->addURL(url.kurl());
+ files = _project->openedFiles();
+ for(it = files.begin(); it!=files.end(); ++it) Main::editorManager().openFile(*it);
+ Register::list().init();
+ QValueList<Register::TypeData> watched = _project->watchedRegisters();
+ QValueList<Register::TypeData>::const_iterator wit;
+ for (wit=watched.begin(); wit!=watched.end(); ++wit) Register::list().setWatched(*wit, true);
+ return true;
+}
+
+bool ProjectManager::View::isExternalFile(const PURL::Url &url) const
+{
+ if ( projectUrl().isEmpty() ) return false;
+ return projectData().externals.contains(url);
+}
+
+void ProjectManager::View::modified(const PURL::Url &url)
+{
+ FileItem *item = findFileItem(url);
+ if ( item && !isExternalFile(url) ) _modified = true;
+}
+
+void ProjectManager::View::renamed(QListViewItem *item, int, const QString &text)
+{
+ Q_ASSERT ( item->rtti()==DeviceRtti );
+ Main::toplevel().setDevice(text);
+}
+
+void ProjectManager::View::updateGUI()
+{
+ _deviceItem->updateText();
+}
+
+QDragObject *ProjectManager::View::dragObject()
+{
+ if ( currentItem()==0 || currentItem()->rtti()!=FileRtti ) return 0;
+ const FileItem *item = static_cast<const FileItem *>(currentItem());
+ const HeaderItem *hitem = static_cast<const HeaderItem *>(item->parent());
+ if ( hitem->group()!=SourceGroup ) return 0;
+ QStrList uris;
+ uris.append(QUriDrag::localFileToUri(item->url().filepath()));
+ return new QUriDrag(uris, viewport());
+}
+
+bool ProjectManager::View::acceptDrag(QDropEvent* e) const
+{
+ if ( e->source()!=viewport() ) return false;
+ const QListViewItem *item = itemAt(e->pos());
+ if ( item==0 || item->rtti()!=FileRtti ) return false;
+ const HeaderItem *hitem = static_cast<const HeaderItem *>(item->parent());
+ return ( hitem->group()==SourceGroup );
+}
+
+void ProjectManager::View::filesReordered()
+{
+ if ( _project==0 ) return;
+ _project->clearFiles();
+ QListViewItem *item = headerItem(SourceGroup)->firstChild();
+ for (;item; item=item->nextSibling())
+ _project->addFile(static_cast<FileItem *>(item)->url());
+}
+
+QString ProjectManager::View::tooltip(QListViewItem *item, int) const
+{
+ switch (Rtti(item->rtti())) {
+ case RootRtti:
+ case FileRtti:
+ case LinkerScriptRtti: return static_cast<const UrlItem *>(item)->url().filepath();
+ case DeviceRtti:
+ case RegisterRtti:
+ case HeaderRtti: break;
+ }
+ return QString::null;
+}
+
+PURL::Url ProjectManager::View::linkerScriptUrl() const
+{
+ QListViewItemIterator it(const_cast<View *>(this));
+ for(; it.current(); ++it) {
+ if ( it.current()->rtti()!=LinkerScriptRtti ) continue;
+ return static_cast<LinkerScriptItem *>(it.current())->url();
+ }
+ return PURL::Url();
+}
+
+bool ProjectManager::View::needsRecompile() const
+{
+ // ### this could be perfected...
+ PURL::Url output = projectUrl().toFileType(PURL::Hex);
+ QDateTime outputLastModified;
+ if ( !output.exists(&outputLastModified) ) return true;
+ PURL::UrlList files;
+ if ( Main::project() ) files = Main::project()->absoluteFiles();
+ else files.append(projectUrl());
+ PURL::UrlList::const_iterator it;
+ for (it=files.begin(); it!=files.end(); ++it) {
+ QDateTime lastModified;
+ if ( !(*it).exists(&lastModified) ) continue;
+ if ( lastModified>outputLastModified ) return true;
+ }
+ return false;
+}
+
+PURL::Url ProjectManager::View::selectedUrl() const
+{
+ QListViewItem *item = currentItem();
+ if ( item==0 ) return PURL::Url();
+ Rtti rtti = Rtti(item->rtti());
+ if ( rtti!=FileRtti ) return PURL::Url();
+ return static_cast<FileItem *>(item)->url();
+}