/* KDevelop Autotools Support Copyright (c) 2001-2002 by Bernd Gehrmann Copyright (c) 2002 by Victor Roeder Copyright (c) 2005 by Matt Rogers *************************************************************************** * * * 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 "autoprojectwidget.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 "kdevcore.h" #include "domutil.h" #include "misc.h" #include "choosetargetdialog.h" #include "autolistviewitems.h" #include "autoprojectpart.h" #include "autosubprojectview.h" #include "autodetailsview.h" #include "urlutil.h" #include "makefilehandler.h" static TQString nicePrimary( const TQString &primary ) { if ( primary == "PROGRAMS" ) return i18n( "Program" ); else if ( primary == "LIBRARIES" ) return i18n( "Library" ); else if ( primary == "LTLIBRARIES" ) return i18n( "Libtool Library" ); else if ( primary == "SCRIPTS" ) return i18n( "Script" ); else if ( primary == "HEADERS" ) return i18n( "Header" ); else if ( primary == "DATA" ) return i18n( "Data" ); else if ( primary == "JAVA" ) return i18n( "Java" ); else return TQString(); } AutoProjectWidget::AutoProjectWidget( AutoProjectPart *part, bool kde ) : TQVBox( 0, "auto project widget" ) { m_part = part; m_kdeMode = kde; m_activeSubproject = 0; m_activeTarget = 0; m_shownSubproject = 0; m_choosenTarget = 0; m_makefileHandler = new MakefileHandler(); TQSplitter *splitter = new TQSplitter(Qt::Vertical, this); initOverview ( splitter ); initDetailview ( splitter ); initActions (); } AutoProjectWidget::~AutoProjectWidget() { delete m_makefileHandler; } void AutoProjectWidget::initOverview ( TQWidget* parent ) { m_subprojectView = new AutoSubprojectView( this, m_part, parent, "project overview widget" ); } void AutoProjectWidget::initDetailview ( TQWidget* parent ) { m_detailView = new AutoDetailsView( this, m_part, parent, "project details widget" ); } void AutoProjectWidget::initActions() { connect( m_subprojectView, TQT_SIGNAL( selectionChanged( TQListViewItem* ) ), this, TQT_SLOT( slotOverviewSelectionChanged( TQListViewItem* ) ) ); } AutoSubprojectView* AutoProjectWidget::getSubprojectView () { return m_subprojectView; } AutoDetailsView* AutoProjectWidget::getDetailsView () { return m_detailView; } void AutoProjectWidget::openProject( const TQString &dirName ) { m_subprojectView->loadMakefileams ( dirName ); MakefileHandler mfh; mfh.parse( m_part->projectDirectory(), true ); } void AutoProjectWidget::closeProject() { m_shownSubproject = 0; m_subprojectView->listView()->clear(); m_detailView->listView()->clear(); } SubprojectItem* AutoProjectWidget::activeSubproject () { return m_activeSubproject; } TargetItem* AutoProjectWidget::activeTarget () { return m_activeTarget; } TQStringList AutoProjectWidget::allSubprojects() { int prefixlen = m_part->projectDirectory().length() + 1; TQStringList res; TQListViewItemIterator it( m_subprojectView->listView() ); for ( ; it.current(); ++it ) { // Skip root subproject // if ( it.current() == m_subprojectView->firstChild() ) // continue; TQString path = static_cast( it.current() ) ->path; res.append( path.mid( prefixlen ) ); } return res; } TQPtrList AutoProjectWidget::allSubprojectItems() { TQPtrList res; TQListViewItemIterator it ( m_subprojectView->listView() ); for ( ; it.current(); ++it ) { // Skip root subproject // if ( it.current() == m_subprojectView->firstChild() ) // continue; SubprojectItem* spitem = static_cast ( it.current() ); res.append ( spitem ); } return res; } SubprojectItem* AutoProjectWidget::subprojectItemForPath(const TQString & path, bool pathIsAbsolute) { kdDebug(9020) << "Looking for path " << path << endl; int prefixLen = m_part->projectDirectory().length() + 1; TQListViewItemIterator it( m_subprojectView->listView() ); for(; it.current(); ++it) { SubprojectItem* spitem = static_cast(it.current() ); TQString relpath = (spitem->path).mid(prefixLen); kdDebug(9020) << " ... checking -" << spitem->path << "-" << endl; kdDebug(9020) << " ... (tailored: -" << relpath << "- against -" << (pathIsAbsolute ? path.mid(prefixLen) : path) << "- )" << endl; if ( relpath == (pathIsAbsolute ? path.mid(prefixLen) : path)) { kdDebug(9020) << "Found it!" << endl; return spitem; } } kdDebug(9020) << "Not found" << endl; return NULL; } TQString AutoProjectWidget::pathForTarget(const TargetItem *titem) const { if (!titem) return TQString(); kdDebug(9020) << "Looking for target " << titem->name << endl; int prefixLen = m_part->projectDirectory().length() + 1; TQListViewItemIterator it( m_subprojectView->listView() ); for(; it.current(); ++it) { SubprojectItem* spitem = static_cast(it.current() ); kdDebug(9020) << "Checking: " << spitem->path << endl; if (spitem->targets.containsRef(titem)) { kdDebug(9020) << "Found it!" << endl; TQString relpath = (spitem->path).mid(prefixLen); return relpath; } } kdDebug(9020) << "Not found" << endl; return TQString(); } TQStringList AutoProjectWidget::allLibraries() { int prefixlen = m_part->projectDirectory().length() + 1; TQStringList res; TQListViewItemIterator it( m_subprojectView->listView() ); for ( ; it.current(); ++it ) { SubprojectItem *spitem = static_cast( it.current() ); TQString path = spitem->path; TQPtrListIterator tit( spitem->targets ); for ( ; tit.current(); ++tit ) { TQString primary = ( *tit ) ->primary; if ( primary == "LIBRARIES" || primary == "LTLIBRARIES" ) { TQString fullname = path + "/" + ( *tit ) ->name; res.append( fullname.mid( prefixlen ) ); } } } return res; } TQStringList AutoProjectWidget::allFiles() { TQPtrStack s; TQMap dict; for ( TQListViewItem * item = m_subprojectView->listView()->firstChild(); item; item = item->nextSibling() ? item->nextSibling() : s.pop() ) { if ( item->firstChild() ) s.push( item->firstChild() ); SubprojectItem *spitem = static_cast( item ); // use URLUtil so paths in root project dir are worked out correctly TQString relPath = URLUtil::relativePath(m_part->projectDirectory(), spitem->path, URLUtil::SLASH_SUFFIX); TQPtrListIterator tit( spitem->targets ); for ( ; tit.current(); ++tit ) { TQPtrListIterator fit( tit.current() ->sources ); for ( ; fit.current(); ++fit ) { if((*fit)->is_subst) continue; TQFileInfo fileInfo( (*fit)->name ); if( fileInfo.extension() == "ui" ) { dict.insert( relPath + fileInfo.baseName() + ".h", true ); dict.insert( relPath + fileInfo.baseName() + ".cpp", true ); } dict.insert( relPath + ( *fit ) ->name, true ); } } } // Files may be in multiple targets, so we have to remove // duplicates TQStringList res; TQMap::Iterator it = dict.begin(); while( it != dict.end() ){ res << it.key(); ++it; } return res; } TQString AutoProjectWidget::subprojectDirectory() { if ( !selectedSubproject() ) return TQString(); return selectedSubproject()->path; } void AutoProjectWidget::setActiveTarget( const TQString &targetPath ) { int prefixlen = m_part->projectDirectory().length() + 1; TQString olddir = m_part->activeDirectory(); m_activeSubproject = 0; m_activeTarget = 0; TQListViewItemIterator it( m_subprojectView->listView() ); for ( ; it.current(); ++it ) { SubprojectItem *spitem = static_cast( it.current() ); TQString path = spitem->path; TQPtrListIterator tit( spitem->targets ); for ( ; tit.current(); ++tit ) { TQString primary = ( *tit ) ->primary; if ( primary != "PROGRAMS" && primary != "LIBRARIES" && primary != "LTLIBRARIES" && primary != "JAVA" ) continue; TQString currentTargetPath = ( path + "/" + ( *tit ) ->name ).mid( prefixlen ); bool hasTarget = ( targetPath == currentTargetPath ); ( *tit )->setBold( hasTarget ); if ( hasTarget ) { spitem->setBold( true ); m_activeSubproject = spitem; m_activeTarget = ( *tit ); m_subprojectView->listView()->setSelected( m_activeSubproject, true ); m_subprojectView->listView()->ensureItemVisible ( m_activeSubproject ); m_subprojectView->listView()->viewport()->update(); m_detailView->listView()->setSelected ( m_activeTarget, true ); m_detailView->listView()->ensureItemVisible ( m_activeTarget ); m_detailView->listView()->viewport()->update(); } else { // to avoid a setBold ( false ) if there's another target in the current Subproject (i.e. spitem) ... spitem->setBold ( ( m_activeSubproject == spitem ) ); m_detailView->listView()->viewport()->update(); } } } if( olddir != m_part->activeDirectory() ) { emit m_part->activeDirectoryChanged( olddir, m_part->activeDirectory() ); } if ( m_activeSubproject == 0 && m_activeTarget == 0 ) { m_subprojectView->listView()->setSelected ( m_subprojectView->listView()->firstChild(), true ); m_subprojectView->listView()->ensureItemVisible ( m_subprojectView->listView()->firstChild() ); m_subprojectView->listView()->viewport()->update(); } } TQString AutoProjectWidget::activeDirectory() { if ( m_activeSubproject ) return m_activeSubproject->path.mid( m_part->projectDirectory().length() + 1 ); else { /* if ( selectedSubproject() ) return selectedSubproject()->path; else*/ return TQString(); } } void AutoProjectWidget::addFiles( const TQStringList &list ) { TQDomDocument &dom = *m_part->projectDom(); TQStringList fileList = list; if ( DomUtil::readBoolEntry( dom, "/kdevautoproject/general/useactivetarget" ) ) { TQStringList::iterator it; TQString fileName; for ( it = fileList.begin(); it != fileList.end(); ++it ) { int pos = ( *it ).findRev('/'); if (pos != -1) fileName = ( *it ).mid(pos+1); else fileName = ( *it ); //FileItem * fitem = createFileItem( fileName,m_activeSubproject ); //m_activeTarget->sources.append( fitem ); //m_activeTarget->insertItem( fitem ); /// @todo Merge with code in addfiledlg.cpp // Check wether a selected subproject+target exists and matches this file // If so use that as target. if( m_detailView->listView()->selectedItem() && m_subprojectView->listView()->selectedItem() ) { TargetItem *titem = dynamic_cast ( m_detailView->listView()->selectedItem() ); SubprojectItem * subitem = dynamic_cast ( m_subprojectView->listView()->selectedItem() ); TQString relativeDir = URLUtil::directory(*it); SubprojectItem* spitem = subprojectItemForPath(relativeDir); if( titem && subitem && subitem == spitem ) { addToTarget(fileName, subitem, titem); }else { addToTarget(fileName, m_activeSubproject, m_activeTarget); } }else { addToTarget(fileName, m_activeSubproject, m_activeTarget); } // TQString canontargetname = AutoProjectTool::canonicalize( m_activeTarget->name ); // TQString varname = canontargetname + "_SOURCES"; // m_activeSubproject->variables[ varname ] += ( " " + fileName ); // // TQMap replaceMap; // replaceMap.insert( varname, m_activeSubproject->variables[ varname ] ); // // AutoProjectTool::addToMakefileam( m_activeSubproject->path + "/Makefile.am", replaceMap ); } emitAddedFiles ( list ); } else { TQStringList doManually, doneAutomatically; // First check wether the detail view has a selected target and the subproject // view selected subproject matches the path of the new file. Then // we can assume the user used the right-click option on the target for( TQStringList::iterator it = fileList.begin(); it != fileList.end(); ++it) { bool autoAdded = false; if( m_detailView->listView()->selectedItem() && m_subprojectView->listView()->selectedItem() ) { TargetItem *titem = dynamic_cast ( m_detailView->listView()->selectedItem() ); SubprojectItem * subitem = dynamic_cast ( m_subprojectView->listView()->selectedItem() ); TQString relativeDir = URLUtil::directory(*it); SubprojectItem* spitem = subprojectItemForPath(relativeDir); if( titem && subitem && subitem == spitem ) { addToTarget(URLUtil::filename(*it), subitem, titem); autoAdded = true; doneAutomatically << *it; } } if(!autoAdded) doManually << *it; } // See if we can figure out the target for each file without asking the user // I think it's a valid assumption that if a directory contains only one target // the file can be added to that target (Julian Rockey linux at jrockey.com) TQStringList temp = doManually; doManually.clear(); for(TQStringList::iterator it = temp.begin();it!=temp.end();++it) { bool autoAdded = false; TQString relativeDir = URLUtil::directory(*it); SubprojectItem* spitem = subprojectItemForPath(relativeDir); if (spitem) { TQPtrList titemList = spitem->targets; if (titemList.count()==1) { addToTarget( URLUtil::filename(*it), spitem, titemList.first() ); doneAutomatically.append(*it); autoAdded = true; } } // add to manual list if this file wasn't auto-added if (!autoAdded) doManually.append(*it); } if (doneAutomatically.count()>0) emitAddedFiles(doneAutomatically); // raise dialog for any files that weren't added automatically if (doManually.count()>0) { ChooseTargetDialog chooseTargetDlg ( this, m_part, doManually, this, "choose target dialog" ); //chooseTargetDlg = new ChooseTargetDialog ( this, this, "choose target dialog" ); if ( chooseTargetDlg.exec() && chooseTargetDlg.alwaysUseActiveTarget() ) DomUtil::writeBoolEntry( dom, "/kdevautoproject/general/useactivetarget", true ); } } } void AutoProjectWidget::addToTarget(const TQString & fileName, SubprojectItem* spitem, TargetItem* titem) { TQString varname; /// \FIXME a quick hack to prevent adding header files to _SOURCES and display them in noinst_HEADERS if (AutoProjectPrivate::isHeader(fileName) && ( titem->primary == "PROGRAMS" || titem->primary == "LIBRARIES" || titem->primary == "LTLIBRARIES" ) ) { kdDebug ( 9020 ) << "Ignoring header file and adding it to noinst_HEADERS: " << fileName << endl; TargetItem* noinst_HEADERS_item = getSubprojectView()->findNoinstHeaders(spitem); FileItem *fitem = createFileItem( fileName, spitem ); noinst_HEADERS_item->sources.append( fitem ); noinst_HEADERS_item->insertItem( fitem ); varname = "noinst_HEADERS"; } else { FileItem * fitem = createFileItem( fileName, spitem ); titem->sources.append( fitem ); titem->insertItem( fitem ); TQString canontargetname = AutoProjectTool::canonicalize( titem->name ); varname = canontargetname + "_SOURCES"; } spitem->variables[ varname ] += ( " " + fileName ); TQMap replaceMap; replaceMap.insert( varname, spitem->variables[ varname ] ); AutoProjectTool::addToMakefileam( spitem->path + "/Makefile.am", replaceMap ); m_detailView->slotSelectionChanged( spitem ); } void AutoProjectWidget::removeFiles( const TQStringList &list ) { Q_UNUSED( list ) } void AutoProjectWidget::slotOverviewSelectionChanged( TQListViewItem *item ) { if ( !item ) return; // Delete the items from the details view first. if ( m_shownSubproject ) { // Remove all TargetItems and all of their tqchildren from the view kdDebug ( 9020 ) << "m_shownSubproject (before takeItem()): " << m_shownSubproject->subdir << endl; TQListViewItem* i = m_detailView->listView()->firstChild(); while( i ) { TQListViewItem* o = i; i = i->nextSibling(); m_detailView->listView()->takeItem(o); } } // We assume here that ALL items in the over list view // are SubprojectItem's m_shownSubproject = dynamic_cast( item ); if ( !m_shownSubproject) return; kdDebug ( 9020 ) << "m_shownSubproject (after takeItem()): " << selectedSubproject()->subdir << endl; // Insert all TargetItems and all of their tqchildren into the view TQPtrListIterator it2( selectedSubproject()->targets ); for ( ; it2.current(); ++it2 ) { kdDebug ( 9020 ) << "insertItem in detail " << ( *it2 )->name << endl; m_detailView->listView()->insertItem( *it2 ); TQPtrListIterator it3( ( *it2 ) ->sources ); for ( ; it3.current(); ++it3 ) ( *it2 )->insertItem( *it3 ); TQString primary = ( *it2 ) ->primary; if ( primary == "PROGRAMS" || primary == "LIBRARIES" || primary == "LTLIBRARIES" || primary == "JAVA" ) ( *it2 ) ->setOpen( true ); } } TargetItem *AutoProjectWidget::selectedTarget() { ProjectItem * pvitem = static_cast( m_detailView->listView()->selectedItem() ); if ( !pvitem || ( pvitem->type() != ProjectItem::Target ) ) return 0; return static_cast( pvitem ); } FileItem *AutoProjectWidget::selectedFile() { ProjectItem * pvitem = static_cast( m_detailView->listView()->selectedItem() ); if ( !pvitem || ( pvitem->type() != ProjectItem::File ) ) return 0; return static_cast( pvitem ); } SubprojectItem* AutoProjectWidget::selectedSubproject() { ProjectItem * pvitem = static_cast ( m_subprojectView->listView()->selectedItem() ); if ( !pvitem || ( pvitem->type() != ProjectItem::Subproject ) ) return 0; return static_cast ( pvitem ); } TargetItem *AutoProjectWidget::createTargetItem( const TQString &name, const TQString &prefix, const TQString &primary, bool take ) { bool docgroup = ( primary == "KDEDOCS" ); bool icongroup = ( primary == "KDEICON" ); bool group = !(docgroup || icongroup); TQString text; if ( docgroup ) text = i18n( "Documentation data" ); else if ( icongroup ) text = i18n( "KDE Icon data" ).tqarg( prefix ); else text = i18n( "%1 (%2 in %3)" ).tqarg( name ).tqarg( nicePrimary( primary ) ).tqarg( prefix ); // Workaround because of TQListView not being able to create // items without actually inserting them TargetItem *titem = new TargetItem( m_detailView->listView(), group, text ); titem->name = name; titem->prefix = prefix; titem->primary = primary; if( take ) m_detailView->listView()->takeItem( titem ); return titem; } FileItem *AutoProjectWidget::createFileItem( const TQString &name, SubprojectItem *subproject ) { bool is_subst; if(name.find("$(") == 0 || name.find("${") == 0) is_subst = true; else is_subst = false; FileItem * fitem = new FileItem( m_subprojectView->listView(), name, is_subst ); fitem->uiFileLink = m_detailView->getUiFileLink(subproject->relativePath()+"/", name ); m_subprojectView->listView()->takeItem( fitem ); fitem->name = name; return fitem; } void AutoProjectWidget::emitAddedFiles( const TQStringList &fileList ) { emit m_part->addedFilesToProject( fileList ); } void AutoProjectWidget::emitAddedFile( const TQString &name ) { TQStringList fileList; fileList.append ( name ); emit m_part->addedFilesToProject( fileList ); } void AutoProjectWidget::emitRemovedFiles( const TQStringList &fileList ) { emit m_part->removedFilesFromProject( fileList ); } void AutoProjectWidget::emitRemovedFile( const TQString &name ) { TQStringList fileList; fileList.append ( name ); emit m_part->removedFilesFromProject( fileList ); } void AutoProjectWidget::restoreSession ( const TQDomElement* el ) { Q_UNUSED( el ); } void AutoProjectWidget::saveSession ( TQDomElement* el ) { if ( m_activeTarget && m_activeSubproject ) { TQDomDocument domDoc = el->ownerDocument(); TQString activeTargetPath = m_activeSubproject->path.mid ( m_part->project()->projectDirectory().length() + 1 ); activeTargetPath = activeTargetPath + "/" + m_activeTarget->name; TQDomElement generalEl = domDoc.createElement("general"); kdDebug ( 9020 ) << k_funcinfo << "Saving session data of AutoProjectWidget: " << activeTargetPath << endl; generalEl.setAttribute("activetarget", activeTargetPath); el->appendChild(generalEl); } } void AutoProjectWidget::setActiveSubproject( SubprojectItem * spitem ) { TQString olddir = m_part->activeDirectory(); m_activeSubproject = spitem; emit m_part->activeDirectoryChanged( olddir, m_part->activeDirectory() ); } void AutoProjectWidget::focusInEvent( TQFocusEvent */*e*/ ) { switch (m_lastFocusedView) { case DetailsView: m_detailView->listView()->setFocus(); break; case SubprojectView: default: m_subprojectView->listView()->setFocus(); } } void AutoProjectWidget::setLastFocusedView( AutoProjectView view ) { m_lastFocusedView = view; } #include "autoprojectwidget.moc" MakefileHandler* AutoProjectWidget::makefileHandler() { return m_makefileHandler; } //kate: indent-mode csands; tab-width 4; space-indent off;