summaryrefslogtreecommitdiffstats
path: root/src/projectmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/projectmanager.cpp')
-rw-r--r--src/projectmanager.cpp1256
1 files changed, 1256 insertions, 0 deletions
diff --git a/src/projectmanager.cpp b/src/projectmanager.cpp
new file mode 100644
index 0000000..dfef6b3
--- /dev/null
+++ b/src/projectmanager.cpp
@@ -0,0 +1,1256 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * 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 "core/ktlconfig.h"
+#include "docmanager.h"
+#include "document.h"
+#include "language.h"
+#include "languagemanager.h"
+#include "ktechlab.h"
+#include "microselectwidget.h"
+#include "programmerdlg.h"
+#include "projectdlgs.h"
+#include "projectmanager.h"
+#include "recentfilesaction.h"
+
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kstandarddirs.h>
+#include <qdom.h>
+#include <qpopupmenu.h>
+#include <qwhatsthis.h>
+
+#include <assert.h>
+
+//BEGIN class LinkerOptions
+LinkerOptions::LinkerOptions()
+{
+ m_hexFormat = HexFormat::inhx32;
+ m_bOutputMapFile = false;
+}
+
+
+QDomElement LinkerOptions::toDomElement( QDomDocument & doc, const KURL & baseURL ) const
+{
+ QDomElement node = doc.createElement("linker");
+
+ node.setAttribute( "hex-format", hexFormatToString(hexFormat()) );
+ node.setAttribute( "output-map-file", outputMapFile() );
+ node.setAttribute( "library-dir", libraryDir() );
+ node.setAttribute( "linker-script", linkerScript() );
+ node.setAttribute( "other", linkerOther() );
+
+ QStringList::const_iterator end = m_linkedInternal.end();
+ for ( QStringList::const_iterator it = m_linkedInternal.begin(); it != end; ++it )
+ {
+ QDomElement child = doc.createElement("linked-internal");
+ node.appendChild(child);
+ child.setAttribute( "url", KURL::relativeURL( baseURL, *it ) );
+ }
+
+ end = m_linkedExternal.end();
+ for ( QStringList::const_iterator it = m_linkedExternal.begin(); it != end; ++it )
+ {
+ QDomElement child = doc.createElement("linked-external");
+ node.appendChild(child);
+ child.setAttribute( "url", *it );
+ }
+
+ return node;
+}
+
+
+void LinkerOptions::domElementToLinkerOptions( const QDomElement & element, const KURL & baseURL )
+{
+ setHexFormat( stringToHexFormat( element.attribute( "hex-format", QString::null ) ) );
+ setOutputMapFile( element.attribute( "output-map-file", "0" ).toInt() );
+ setLibraryDir( element.attribute( "library-dir", QString::null ) );
+ setLinkerScript( element.attribute( "linker-script", QString::null ) );
+ setLinkerOther( element.attribute( "other", QString::null ) );
+
+ m_linkedInternal.clear();
+ m_linkedExternal.clear();
+
+ QDomNode node = element.firstChild();
+ while ( !node.isNull() )
+ {
+ QDomElement childElement = node.toElement();
+ if ( !childElement.isNull() )
+ {
+ const QString tagName = childElement.tagName();
+
+ if ( tagName == "linked-internal" )
+ m_linkedInternal << KURL( baseURL, childElement.attribute( "url", QString::null ) ).url();
+
+ else if ( tagName == "linked-external" )
+ m_linkedExternal << childElement.attribute( "url", QString::null );
+
+ else
+ kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
+ }
+
+ node = node.nextSibling();
+ }
+}
+
+
+QString LinkerOptions::hexFormatToString( HexFormat::type hexFormat )
+{
+ switch ( hexFormat )
+ {
+ case HexFormat::inhx32:
+ return "inhx32";
+
+ case HexFormat::inhx8m:
+ return "inhx8m";
+
+ case HexFormat::inhx8s:
+ return "inhx8s";
+
+ case HexFormat::inhx16:
+ return "inhx16";
+ }
+
+ // Default hex format is inhx32
+ return "inhx32";
+}
+
+
+LinkerOptions::HexFormat::type LinkerOptions::stringToHexFormat( const QString & hexFormat )
+{
+ if ( hexFormat == "inhx8m" )
+ return HexFormat::inhx8m;
+
+ if ( hexFormat == "inhx8s" )
+ return HexFormat::inhx8s;
+
+ if ( hexFormat == "inhx16" )
+ return HexFormat::inhx16;
+
+ return HexFormat::inhx32;
+}
+//END class LinkerOptions
+
+
+
+//BEGIN class ProcessingOptions
+ProcessingOptions::ProcessingOptions()
+{
+ m_bUseParentMicroID = false;
+ m_microID = "P16F84";
+}
+
+
+ProcessingOptions::~ProcessingOptions()
+{
+}
+
+
+QDomElement ProcessingOptions::toDomElement( QDomDocument & doc, const KURL & baseURL ) const
+{
+ QDomElement node = doc.createElement("processing");
+
+ node.setAttribute( "output", KURL::relativeURL( baseURL, outputURL().url() ) );
+ node.setAttribute( "micro", m_microID );
+
+ return node;
+}
+
+
+void ProcessingOptions::domElementToProcessingOptions( const QDomElement & element, const KURL & baseURL )
+{
+ setOutputURL( KURL( baseURL, element.attribute( "output", QString::null ) ) );
+ setMicroID( element.attribute("micro", QString::null ) );
+}
+//END class ProcessingOptions
+
+
+
+//BEGIN class ProjectItem
+ProjectItem::ProjectItem( ProjectItem * parent, Type type, ProjectManager * projectManager, KTechlab * ktechlab )
+ : QObject()
+{
+ m_pParent = parent;
+ m_pILVItem = 0l;
+ m_pProjectManager = projectManager;
+ p_ktechlab = ktechlab;
+ m_type = type;
+}
+
+
+ProjectItem::~ProjectItem()
+{
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::iterator end = m_children.end();
+ for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
+ (*it)->deleteLater();
+ m_children.clear();
+
+ delete m_pILVItem;
+ m_pILVItem = 0l;
+}
+
+
+void ProjectItem::setILVItem( ILVItem * ilvItem )
+{
+ m_pILVItem = ilvItem;
+ ilvItem->setOpen(true);
+ ilvItem->setText( 0, name() );
+ ilvItem->setProjectItem(this);
+ updateILVItemPixmap();
+}
+
+
+void ProjectItem::updateILVItemPixmap()
+{
+ if ( !m_pILVItem )
+ return;
+
+ switch ( type() )
+ {
+ case ProjectType:
+ {
+ // ?! - We shouldn't have an ilvitem for this.
+ break;
+ }
+
+ case ProgramType:
+ {
+ QPixmap pm;
+ pm.load( locate( "appdata", "icons/project_program.png" ) );
+ m_pILVItem->setPixmap( 0, pm );
+ break;
+ }
+
+ case LibraryType:
+ {
+ QPixmap pm;
+ pm.load( locate( "appdata", "icons/project_library.png" ) );
+ m_pILVItem->setPixmap( 0, pm );
+ break;
+ }
+
+ case FileType:
+ {
+ KMimeType::Ptr m = KMimeType::findByPath( url().path() );
+ m_pILVItem->setPixmap( 0, m->pixmap( KIcon::Small ) );
+ break;
+ }
+ }
+}
+
+
+void ProjectItem::addChild( ProjectItem * child )
+{
+ if ( !child || m_children.contains(child) )
+ return;
+
+ m_children << child;
+
+ child->setILVItem( m_pILVItem ?
+ new ILVItem( m_pILVItem, child->name() ) :
+ new ILVItem( m_pProjectManager, name() ) );
+
+ updateControlChildMicroIDs();
+}
+
+
+void ProjectItem::updateControlChildMicroIDs()
+{
+ bool control = false;
+ switch ( type() )
+ {
+ case ProjectItem::ProjectType:
+ case ProjectItem::LibraryType:
+ case ProjectItem::ProgramType:
+ control = !microID().isEmpty();
+ break;
+
+ case ProjectItem::FileType:
+ control = true;
+ break;
+ }
+
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::iterator end = m_children.end();
+ for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
+ (*it)->setUseParentMicroID( control );
+}
+
+
+void ProjectItem::setName( const QString & name )
+{
+ m_name = name;
+ if (m_pILVItem)
+ m_pILVItem->setText( 0, name );
+}
+
+
+void ProjectItem::setURL( const KURL & url )
+{
+ m_url = url;
+
+ if ( m_name.isEmpty() )
+ setName( url.fileName() );
+
+ if ( type() != FileType )
+ {
+ // The output url *is* our url
+ setOutputURL(url);
+ }
+ else if ( outputURL().isEmpty() )
+ {
+ // Try and guess what the output url should be...
+ QString newExtension;
+
+ switch ( outputType() )
+ {
+ case ProgramOutput:
+ newExtension = ".hex";
+ break;
+
+ case ObjectOutput:
+ newExtension = ".o";
+ break;
+
+ case LibraryOutput:
+ newExtension = ".o";
+ break;
+
+ case UnknownOutput:
+ break;
+ }
+
+ if ( !newExtension.isEmpty() )
+ {
+ const QString fileName = url.url();
+ QString extension = fileName.right( fileName.length() - fileName.findRev('.') );
+ setOutputURL( QString(fileName).replace( extension, newExtension ) );
+ }
+ }
+
+ updateILVItemPixmap();
+}
+
+
+QString ProjectItem::microID() const
+{
+ if ( !m_bUseParentMicroID )
+ return m_microID;
+
+ return m_pParent ? m_pParent->microID() : QString::null;
+}
+
+
+void ProjectItem::setMicroID( const QString & id )
+{
+ ProcessingOptions::setMicroID(id);
+ updateControlChildMicroIDs();
+}
+
+
+ProjectItem::OutputType ProjectItem::outputType() const
+{
+ if ( !m_pParent )
+ return UnknownOutput;
+
+ switch ( m_pParent->type() )
+ {
+ case ProjectItem::ProjectType:
+ {
+ // We're a top level build target, so look at our own type
+ switch ( type() )
+ {
+ case ProjectItem::ProjectType:
+ kdWarning() << k_funcinfo << "Parent item and this item are both project items" << endl;
+ return UnknownOutput;
+
+ case ProjectItem::FileType:
+ case ProjectItem::ProgramType:
+ return ProgramOutput;
+
+ case ProjectItem::LibraryType:
+ return LibraryOutput;
+ }
+ return UnknownOutput;
+ }
+
+ case ProjectItem::FileType:
+ {
+ kdWarning() << k_funcinfo << "Don't know how to handle parent item being a file" << endl;
+ return UnknownOutput;
+ }
+
+ case ProjectItem::ProgramType:
+ case ProjectItem::LibraryType:
+ return ObjectOutput;
+ }
+
+ return UnknownOutput;
+}
+
+
+bool ProjectItem::build( ProcessOptionsList * pol )
+{
+ if ( !pol )
+ return false;
+
+ // Check to see that we aren't already in the ProcessOptionstList;
+ ProcessOptionsList::iterator polEnd = pol->end();
+ for ( ProcessOptionsList::iterator it = pol->begin(); it != polEnd; ++it )
+ {
+ if ( (*it).targetFile() == outputURL().path() )
+ return true;
+ }
+
+ ProjectInfo * projectInfo = ProjectManager::self()->currentProject();
+ assert(projectInfo);
+
+ if ( outputURL().isEmpty() )
+ {
+ KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (output url is empty).").arg(name()) );
+ return false;
+ }
+
+ // Build all internal libraries that we depend on
+ QStringList::iterator send = m_linkedInternal.end();
+ for ( QStringList::iterator it = m_linkedInternal.begin(); it != send; ++it )
+ {
+ ProjectItem * lib = projectInfo->findItem( projectInfo->directory() + *it );
+ if ( !lib )
+ {
+ KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (library does not exist in project).").arg(*it) );
+ return false;
+ }
+
+ if ( !lib->build(pol) )
+ return false;
+ }
+
+
+ // Build all children
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::iterator cend = m_children.end();
+ for ( ProjectItemList::iterator it = m_children.begin(); it != cend; ++it )
+ {
+ if ( ! (*it)->build(pol) )
+ return false;
+ }
+
+
+ // Now build ourself
+ ProcessOptions po;
+ po.b_addToProject = false;
+ po.setTargetFile( outputURL().path() );
+ po.m_picID = microID();
+
+ ProcessOptions::ProcessPath::MediaType typeTo;
+
+ switch ( outputType() )
+ {
+ case UnknownOutput:
+ KMessageBox::sorry( 0l, i18n("Don't know how to build \"%1\" (unknown output type).").arg(name()) );
+ return false;
+
+ case ProgramOutput:
+ typeTo = ProcessOptions::ProcessPath::Program;
+ break;
+
+ case ObjectOutput:
+ typeTo = ProcessOptions::ProcessPath::Object;
+ break;
+
+ case LibraryOutput:
+ typeTo = ProcessOptions::ProcessPath::Library;
+ break;
+ }
+
+ switch ( type() )
+ {
+ case ProjectType:
+ // Nothing to do
+ return true;
+
+ case FileType:
+ po.setInputFiles( url().path() );
+ po.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::guessMediaType( url().url() ), typeTo ) );
+ break;
+
+ case ProgramType:
+ case LibraryType:
+ // Build up a list of input urls
+ QStringList inputFiles;
+
+ // Link child objects
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::iterator cend = m_children.end();
+ for ( ProjectItemList::iterator it = m_children.begin(); it != cend; ++it )
+ inputFiles << (*it)->outputURL().path();
+
+ po.setInputFiles(inputFiles);
+ po.setProcessPath( ProcessOptions::ProcessPath::path( ProcessOptions::ProcessPath::Object, typeTo ) );
+ break;
+ }
+
+ po.m_hexFormat = hexFormatToString( hexFormat() );
+ po.m_bOutputMapFile = outputMapFile();
+ po.m_libraryDir = libraryDir();
+ po.m_linkerScript = linkerScript();
+ po.m_linkOther = linkerOther();
+
+ // Link against libraries
+ QStringList::iterator lend = m_linkedInternal.end();
+ for ( QStringList::iterator it = m_linkedInternal.begin(); it != lend; ++it )
+ po.m_linkLibraries += projectInfo->directory() + *it;
+ lend = m_linkedExternal.end();
+ for ( QStringList::iterator it = m_linkedExternal.begin(); it != lend; ++it )
+ po.m_linkLibraries += *it;
+
+ // Save our working file (if open) and append to the build list
+ Document * currentDoc = DocManager::self()->findDocument( url() );
+ if (currentDoc)
+ currentDoc->fileSave();
+ pol->append(po);
+
+ return true;
+}
+
+
+void ProjectItem::upload( ProcessOptionsList * pol )
+{
+ build( pol );
+
+ ProgrammerDlg * dlg = new ProgrammerDlg( microID(), (QWidget*)p_ktechlab, "Programmer Dlg" );
+
+ dlg->exec();
+ if ( !dlg->isAccepted() )
+ {
+ dlg->deleteLater();
+ return;
+ }
+
+ ProcessOptions po;
+ dlg->initOptions( & po );
+ po.b_addToProject = false;
+ po.setInputFiles( outputURL().path() );
+ po.setProcessPath( ProcessOptions::ProcessPath::Program_PIC );
+
+ pol->append( po );
+
+ dlg->deleteLater();
+}
+
+
+QDomElement ProjectItem::toDomElement( QDomDocument & doc, const KURL & baseURL ) const
+{
+ QDomElement node = doc.createElement("item");
+
+ node.setAttribute( "type", typeToString() );
+ node.setAttribute( "name", m_name );
+ node.setAttribute( "url", KURL::relativeURL( baseURL, m_url.url() ) );
+
+ node.appendChild( LinkerOptions::toDomElement( doc, baseURL ) );
+ node.appendChild( ProcessingOptions::toDomElement( doc, baseURL ) );
+
+
+ ProjectItemList::const_iterator end = m_children.end();
+ for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
+ {
+ if (*it)
+ node.appendChild( (*it)->toDomElement( doc, baseURL ) );
+ }
+
+ return node;
+}
+
+
+KURL::List ProjectItem::childOutputURLs( unsigned types, unsigned outputTypes ) const
+{
+ KURL::List urls;
+
+ ProjectItemList::const_iterator end = m_children.end();
+ for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
+ {
+ if (!*it)
+ continue;
+
+ if ( ((*it)->type() & types) && ((*it)->outputType() & outputTypes) )
+ urls += (*it)->outputURL().prettyURL();
+
+ urls += (*it)->childOutputURLs(types);
+ }
+
+ return urls;
+}
+
+
+ProjectItem * ProjectItem::findItem( const KURL & url )
+{
+ if ( this->url() == url )
+ return this;
+
+ ProjectItemList::const_iterator end = m_children.end();
+ for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
+ {
+ if (!*it)
+ continue;
+
+ ProjectItem * found = (*it)->findItem(url);
+ if (found)
+ return found;
+ }
+
+ return 0l;
+}
+
+
+bool ProjectItem::closeOpenFiles()
+{
+ Document * doc = DocManager::self()->findDocument(m_url);
+ if ( doc && !doc->fileClose() )
+ return false;
+
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::iterator end = m_children.end();
+ for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
+ {
+ if ( !(*it)->closeOpenFiles() )
+ return false;
+ }
+
+ return true;
+}
+
+
+void ProjectItem::addFiles()
+{
+ KURL::List urls = p_ktechlab->getFileURLs();
+ const KURL::List::iterator end = urls.end();
+ for ( KURL::List::iterator it = urls.begin(); it != end; ++ it)
+ addFile(*it);
+}
+
+
+void ProjectItem::addCurrentFile()
+{
+ Document *document = DocManager::self()->getFocusedDocument();
+ if (!document)
+ return;
+
+ // If the file isn't saved yet, we must do that
+ // before it is added to the project.
+ if( document->url().isEmpty() )
+ {
+ document->fileSaveAs();
+ // If the user pressed cancel then just give up,
+ // otherwise the file can now be added.
+ }
+
+ if( !document->url().isEmpty() )
+ addFile( document->url() );
+}
+
+
+void ProjectItem::addFile( const KURL & url )
+{
+ if ( url.isEmpty() )
+ return;
+
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::iterator end = m_children.end();
+ for ( ProjectItemList::iterator it = m_children.begin(); it != end; ++it )
+ {
+ if ( (*it)->type() == FileType && (*it)->url() == url )
+ return;
+ }
+
+ ProjectItem * item = new ProjectItem( this, FileType, m_pProjectManager, p_ktechlab );
+ item->setURL(url);
+ addChild(item);
+}
+
+
+QString ProjectItem::typeToString() const
+{
+ switch (m_type)
+ {
+ case ProjectType:
+ return "Project";
+
+ case FileType:
+ return "File";
+
+ case ProgramType:
+ return "Program";
+
+ case LibraryType:
+ return "Library";
+ }
+ return QString::null;
+}
+
+
+ProjectItem::Type ProjectItem::stringToType( const QString & type )
+{
+ if ( type == "Project" )
+ return ProjectType;
+
+ if ( type == "File" )
+ return FileType;
+
+ if ( type == "Program" )
+ return ProgramType;
+
+ if ( type == "Library" )
+ return LibraryType;
+
+ return FileType;
+}
+
+
+void ProjectItem::domElementToItem( const QDomElement & element, const KURL & baseURL )
+{
+ Type type = stringToType( element.attribute( "type", QString::null ) );
+ QString name = element.attribute( "name", QString::null );
+ KURL url( baseURL, element.attribute( "url", QString::null ) );
+
+ ProjectItem * createdItem = new ProjectItem( this, type, m_pProjectManager, p_ktechlab );
+ createdItem->setName( name );
+ createdItem->setURL( url );
+
+ addChild( createdItem );
+
+ QDomNode node = element.firstChild();
+ while ( !node.isNull() )
+ {
+ QDomElement childElement = node.toElement();
+ if ( !childElement.isNull() )
+ {
+ const QString tagName = childElement.tagName();
+
+ if ( tagName == "linker" )
+ createdItem->domElementToLinkerOptions( childElement, baseURL );
+
+ else if ( tagName == "processing" )
+ createdItem->domElementToProcessingOptions( childElement, baseURL );
+
+ else if ( tagName == "item" )
+ createdItem->domElementToItem( childElement, baseURL );
+
+ else
+ kdError() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
+ }
+
+ node = node.nextSibling();
+ }
+}
+//END class ProjectItem
+
+
+
+//BEGIN class ProjectInfo
+ProjectInfo::ProjectInfo( ProjectManager * projectManager, KTechlab * ktechlab )
+ : ProjectItem( 0l, ProjectItem::ProjectType, projectManager, ktechlab )
+{
+ m_microID = QString::null;
+}
+
+
+ProjectInfo::~ ProjectInfo()
+{
+}
+
+
+bool ProjectInfo::open( const KURL & url )
+{
+ QString target;
+ if ( !KIO::NetAccess::download( url, target, 0l ) )
+ {
+ // If the file could not be downloaded, for example does not
+ // exist on disk, NetAccess will tell us what error to use
+ KMessageBox::error( 0l, KIO::NetAccess::lastErrorString() );
+
+ return false;
+ }
+
+ QFile file(target);
+ if ( !file.open( IO_ReadOnly ) )
+ {
+ KMessageBox::sorry( 0l, i18n("Could not open %1 for reading").arg(target) );
+ return false;
+ }
+
+ m_url = url;
+
+ QString xml;
+ QTextStream textStream( &file );
+ while ( !textStream.eof() )
+ xml += textStream.readLine() + '\n';
+
+ file.close();
+
+ QDomDocument doc( "KTechlab" );
+ QString errorMessage;
+ if ( !doc.setContent( xml, &errorMessage ) )
+ {
+ KMessageBox::sorry( 0l, i18n("Couldn't parse xml:\n%1").arg(errorMessage) );
+ return false;
+ }
+
+ QDomElement root = doc.documentElement();
+
+ QDomNode node = root.firstChild();
+ while ( !node.isNull() )
+ {
+ QDomElement element = node.toElement();
+ if ( !element.isNull() )
+ {
+ const QString tagName = element.tagName();
+
+ if ( tagName == "linker" )
+ domElementToLinkerOptions( element, m_url );
+
+ else if ( tagName == "processing" )
+ domElementToProcessingOptions( element, m_url );
+
+ else if ( tagName == "file" || tagName == "item" )
+ domElementToItem( element, m_url );
+
+ else
+ kdWarning() << k_funcinfo << "Unrecognised element tag name: "<<tagName<<endl;
+ }
+
+ node = node.nextSibling();
+ }
+
+ updateControlChildMicroIDs();
+ return true;
+}
+
+
+bool ProjectInfo::save()
+{
+ QFile file( m_url.path() );
+ if ( file.open(IO_WriteOnly) == false )
+ {
+ KMessageBox::sorry( NULL, i18n("Project could not be saved to \"%1\"").arg(m_url.path()), i18n("Saving Project") );
+ return false;
+ }
+
+ QDomDocument doc("KTechlab");
+
+ QDomElement root = doc.createElement("project");
+ doc.appendChild(root);
+
+// root.appendChild( LinkerOptions::toDomElement(doc) );
+// root.appendChild( ProcessingOptions::toDomElement(doc) );
+
+ m_children.remove( (ProjectItem*)0l );
+ ProjectItemList::const_iterator end = m_children.end();
+ for ( ProjectItemList::const_iterator it = m_children.begin(); it != end; ++it )
+ root.appendChild( (*it)->toDomElement( doc, m_url ) );
+
+ QTextStream stream(&file);
+ stream << doc.toString();
+ file.close();
+
+ (static_cast<RecentFilesAction*>(p_ktechlab->action("project_open_recent")))->addURL(m_url);
+
+ return true;
+}
+
+
+bool ProjectInfo::saveAndClose()
+{
+ if (!save())
+ return false;
+
+ if (!closeOpenFiles())
+ return false;
+
+ return true;
+}
+//END class ProjectInfo
+
+
+
+//BEGIN class ProjectManager
+ProjectManager * ProjectManager::m_pSelf = 0l;
+
+ProjectManager * ProjectManager::self( KTechlab * ktl, KateMDI::ToolView * parent )
+{
+ if ( !m_pSelf )
+ {
+ assert(ktl);
+ assert(parent);
+ m_pSelf = new ProjectManager( ktl, parent );
+ }
+ return m_pSelf;
+}
+
+
+ProjectManager::ProjectManager( KTechlab * ktl, KateMDI::ToolView * parent )
+ : ItemSelector( parent, "Project Manager" ),
+ m_pCurrentProject(0l),
+ p_ktechlab(ktl)
+{
+ QWhatsThis::add( this, i18n("Displays the list of files in the project.\nTo open or close a project, use the \"Project\" menu. Right click on a file to remove it from the project") );
+
+ setListCaption( i18n("File") );
+ setCaption( i18n("Project Manager") );
+
+ connect( this, SIGNAL(clicked(QListViewItem*)), this, SLOT(slotItemClicked(QListViewItem*)) );
+}
+
+
+ProjectManager::~ProjectManager()
+{
+}
+
+
+void ProjectManager::slotNewProject()
+{
+ if ( !slotCloseProject() )
+ return;
+
+ NewProjectDlg *newProjectDlg = new NewProjectDlg(this);
+ newProjectDlg->exec();
+
+ if ( newProjectDlg->accepted() )
+ {
+ m_pCurrentProject = new ProjectInfo( this, p_ktechlab );
+ m_pCurrentProject->setName( newProjectDlg->projectName() );
+ m_pCurrentProject->setURL( newProjectDlg->location() + m_pCurrentProject->name().lower() + ".ktechlab" );
+
+ QDir dir;
+ if ( !dir.mkdir( m_pCurrentProject->directory() ) )
+ kdDebug() << "Error in creating directory " << m_pCurrentProject->directory() << endl;
+
+ m_pCurrentProject->save();
+ updateActions();
+
+ emit projectCreated();
+ }
+
+ delete newProjectDlg;
+}
+
+
+void ProjectManager::slotProjectOptions()
+{
+}
+
+
+void ProjectManager::slotOpenProject()
+{
+ KURL url = KFileDialog::getOpenURL(QString::null,
+ "*.ktechlab|KTechlab Project(*.ktechlab)\n*|All Files", this, i18n("Open Location"));
+
+ if ( url.isEmpty() )
+ return;
+
+ slotOpenProject(url);
+}
+
+
+void ProjectManager::slotOpenProject( const KURL & url )
+{
+ if ( m_pCurrentProject && m_pCurrentProject->url() == url )
+ return;
+
+ if ( !slotCloseProject() )
+ return;
+
+ m_pCurrentProject = new ProjectInfo( this, p_ktechlab );
+
+ if ( !m_pCurrentProject->open(url) )
+ {
+ m_pCurrentProject->deleteLater();
+ m_pCurrentProject = 0l;
+ return;
+ }
+
+ RecentFilesAction * rfa = static_cast<RecentFilesAction*>(p_ktechlab->action("project_open_recent"));
+ rfa->addURL( m_pCurrentProject->url() );
+
+ if ( KTLConfig::raiseItemSelectors() )
+ p_ktechlab->showToolView( p_ktechlab->toolView( toolViewIdentifier() ) );
+
+ updateActions();
+ emit projectOpened();
+}
+
+
+bool ProjectManager::slotCloseProject()
+{
+ if ( !m_pCurrentProject )
+ return true;
+
+ if ( !m_pCurrentProject->saveAndClose() )
+ return false;
+
+ m_pCurrentProject->deleteLater();
+ m_pCurrentProject = 0l;
+ updateActions();
+ emit projectClosed();
+ return true;
+}
+
+
+void ProjectManager::slotCreateSubproject()
+{
+ if ( !currentProject() )
+ return;
+
+ CreateSubprojectDlg * dlg = new CreateSubprojectDlg(this);
+ dlg->exec();
+
+ if ( dlg->accepted() )
+ {
+ ProjectItem::Type type = ProjectItem::ProgramType;
+ switch ( dlg->type() )
+ {
+ case CreateSubprojectDlg::ProgramType:
+ type = ProjectItem::ProgramType;
+ break;
+
+ case CreateSubprojectDlg::LibraryType:
+ type = ProjectItem::LibraryType;
+ break;
+ }
+
+ ProjectItem * subproject = new ProjectItem( currentProject(), type, this, p_ktechlab );
+ subproject->setURL( dlg->targetFile() );
+
+ currentProject()->addChild(subproject);
+ currentProject()->save();
+
+ emit subprojectCreated();
+ }
+
+ delete dlg;
+}
+
+
+void ProjectManager::updateActions()
+{
+ bool projectIsOpen = m_pCurrentProject;
+
+ p_ktechlab->action("project_create_subproject")->setEnabled( projectIsOpen );
+ p_ktechlab->action("project_export_makefile")->setEnabled( projectIsOpen );
+ p_ktechlab->action("subproject_add_existing_file")->setEnabled( projectIsOpen );
+ p_ktechlab->action("subproject_add_current_file")->setEnabled( projectIsOpen );
+// p_ktechlab->action("project_options")->setEnabled( projectIsOpen );
+ p_ktechlab->action("project_close")->setEnabled( projectIsOpen );
+ p_ktechlab->action("project_add_existing_file")->setEnabled( projectIsOpen );
+ p_ktechlab->action("project_add_current_file")->setEnabled( projectIsOpen );
+}
+
+
+void ProjectManager::slotAddFile()
+{
+ if ( !currentProject() )
+ return;
+
+ currentProject()->addFiles();
+ emit filesAdded();
+}
+
+
+void ProjectManager::slotAddCurrentFile()
+{
+ if ( !currentProject() )
+ return;
+ currentProject()->addCurrentFile();
+ emit filesAdded();
+}
+
+
+void ProjectManager::slotSubprojectAddExistingFile()
+{
+ ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem || !currentItem->projectItem() )
+ return;
+
+ currentItem->projectItem()->addFiles();
+ emit filesAdded();
+}
+
+
+void ProjectManager::slotSubprojectAddCurrentFile()
+{
+ ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem || !currentItem->projectItem() )
+ return;
+
+ currentItem->projectItem()->addCurrentFile();
+ emit filesAdded();
+}
+
+
+void ProjectManager::slotItemBuild()
+{
+ ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem || !currentItem->projectItem() )
+ return;
+
+ ProcessOptionsList pol;
+ currentItem->projectItem()->build(&pol);
+ LanguageManager::self()->compile(pol);
+}
+
+
+void ProjectManager::slotItemUpload()
+{
+ ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem || !currentItem->projectItem() )
+ return;
+
+ ProcessOptionsList pol;
+ currentItem->projectItem()->upload(&pol);
+ LanguageManager::self()->compile(pol);
+}
+
+
+void ProjectManager::slotRemoveSelected()
+{
+ ILVItem *currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem )
+ return;
+
+ int choice = KMessageBox::questionYesNo( this, i18n("Do you really want to remove \"%1\"?").arg( currentItem->text(0) ), i18n("Remove Project File?"), KGuiItem(i18n("Remove")), KGuiItem(i18n("Cancel")) );
+
+ if ( choice == KMessageBox::No )
+ return;
+
+ currentItem->projectItem()->deleteLater();
+ emit filesRemoved();
+}
+
+
+void ProjectManager::slotExportToMakefile()
+{
+}
+
+
+void ProjectManager::slotSubprojectLinkerOptions()
+{
+ ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem || !currentItem->projectItem() )
+ return;
+
+ LinkerOptionsDlg * dlg = new LinkerOptionsDlg( currentItem->projectItem(), this );
+ dlg->exec();
+ currentProject()->save();
+
+ // The dialog sets the options for us if it was accepted, so we don't need to do anything
+ delete dlg;
+}
+
+
+void ProjectManager::slotItemProcessingOptions()
+{
+ ILVItem * currentItem = dynamic_cast<ILVItem*>(selectedItem());
+ if ( !currentItem || !currentItem->projectItem() )
+ return;
+
+ ProcessingOptionsDlg * dlg = new ProcessingOptionsDlg( currentItem->projectItem(), this );
+ dlg->exec();
+ currentProject()->save();
+
+ // The dialog sets the options for us if it was accepted, so we don't need to do anything
+ delete dlg;
+}
+
+
+void ProjectManager::slotItemClicked( QListViewItem * item )
+{
+ ILVItem * ilvItem = dynamic_cast<ILVItem*>(item);
+ if ( !ilvItem )
+ return;
+
+ ProjectItem * projectItem = ilvItem->projectItem();
+ if ( !projectItem || projectItem->type() != ProjectItem::FileType )
+ return;
+
+ DocManager::self()->openURL( projectItem->url() );
+}
+
+
+void ProjectManager::slotContextMenuRequested( QListViewItem * item, const QPoint& pos, int /*col*/ )
+{
+ QString popupName;
+ ILVItem * ilvItem = dynamic_cast<ILVItem*>(item);
+ KAction * linkerOptionsAct = p_ktechlab->action("project_item_linker_options");
+ linkerOptionsAct->setEnabled(false);
+
+ if ( !m_pCurrentProject )
+ popupName = "project_none_popup";
+
+ else if ( !ilvItem )
+ popupName = "project_blank_popup";
+
+ else
+ {
+ ProcessOptions::ProcessPath::MediaType mediaType = ProcessOptions::guessMediaType( ilvItem->projectItem()->url().url() );
+
+ switch ( ilvItem->projectItem()->type() )
+ {
+ case ProjectItem::FileType:
+ if ( mediaType == ProcessOptions::ProcessPath::Unknown )
+ popupName = "project_file_other_popup";
+ else
+ popupName = "project_file_popup";
+ break;
+
+ case ProjectItem::ProgramType:
+ popupName = "project_program_popup";
+ break;
+
+ case ProjectItem::LibraryType:
+ popupName = "project_library_popup";
+ break;
+
+ case ProjectItem::ProjectType:
+ return;
+ }
+ switch ( ilvItem->projectItem()->outputType() )
+ {
+ case ProjectItem::ProgramOutput:
+ linkerOptionsAct->setEnabled(true);
+ break;
+
+ case ProjectItem::ObjectOutput:
+ case ProjectItem::LibraryOutput:
+ case ProjectItem::UnknownOutput:
+ linkerOptionsAct->setEnabled(false);
+ break;
+ }
+
+ // Only have linking options for SDCC files
+ linkerOptionsAct->setEnabled( mediaType == ProcessOptions::ProcessPath::C );
+ }
+
+ bool haveFocusedDocument = DocManager::self()->getFocusedDocument();
+ p_ktechlab->action("subproject_add_current_file")->setEnabled( haveFocusedDocument );
+ p_ktechlab->action("project_add_current_file")->setEnabled( haveFocusedDocument );
+
+ QPopupMenu *pop = static_cast<QPopupMenu*>(p_ktechlab->factory()->container( popupName, p_ktechlab ));
+ if (pop)
+ pop->popup(pos);
+}
+//END class ProjectManager
+
+#include "projectmanager.moc"