#include "PikMain.h"
#include <qapplication.h>

#include <qmessagebox.h>
#include <qpixmap.h>
#include <qiconset.h>
#include <qtoolbutton.h>
#include <qmultilineedit.h>
#include <qlayout.h>
#include <qsplitter.h>
#include <qtextview.h>
#include <qregexp.h>
#include <qstringlist.h>
#include <qdatetime.h>
#include <qtimer.h>
#include <qregexp.h>


#include <ktabctl.h>
#include <keditcl.h>
#include <ktoolbar.h>
#include <kpopupmenu.h>
#include <kstatusbar.h>
#include <klocale.h>
#include <klocale.h>
#include <kedittoolbar.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kaction.h>
#include <kmessagebox.h>

#include <kcmdlineargs.h>

#include "PrgWid.h"
#include "ProjectWid.h"
#include "ConfigCenter.h"
#include "pic.hh"

#include <stdio.h>
#include <qfileinfo.h>
#include <qfile.h>
#include <qtextstream.h>

#include "TestWindow.h"
#include "FNU.h"
#include "BinValueEditor.h"
#include "Project.h"
#include "Config.h"
#include "PrgConfigWidget.h"
#include "BuiltinProgrammer.h"
#include "pkpProgrammer.h"
#include "pk2Programmer.h"
#include "pk2cmdProgrammer.h"


#include <iostream>
#include <assert.h>
using namespace std ;

#include "../config.h"

PikMain::PikMain() : KMainWindow(0,"PikMain") ,
        programmer_widget(0),   project_wid(0) ,  config_center(0) , current_programmer(0)
{
    setCaption(       KApplication::kApplication()->makeStdCaption( i18n("PicMicro IDE")  )  );

    //
    // verify version number
    //
    QString oldversion ;
    Config::getGlobal(oldversion) ;
    if( oldversion != VERSION)
    {
        QMessageBox::information(this,
                                 i18n("New version detected"),
                                 i18n("\nPiKdev version has changed from %2 to %1.\n\n"
                                      "The following old (local) ressource files will be deleted:\n\n"
                                      "  ~/.kde/share/apps/pikdev/pikdev-main.rc\n"
                                      "  ~/.kde/share/apps/pikdev/pikdev-prg.rc\n"
                                      "\nThis operation is necessary to update the user interface.\n"
                                     ).arg(VERSION).arg(oldversion)
                                 , i18n( "OK")) ;

        const char *h = getenv("HOME") ;
        if( h)
        {
            QString  rcfile(h) ;
            rcfile +=  "/.kde/share/apps/pikdev/pikdev-main.rc"   ;
            remove
                (rcfile.latin1()) ;
            rcfile = h ;
            rcfile +=  "/.kde/share/apps/pikdev/pikdev-prg.rc"   ;
            remove
                (rcfile.latin1()) ;
        }
        Config::setGlobal(VERSION) ;

    }

    // ----------------------------------------------------
    // create programmers pool
    the_programmers.push_back(new BuiltinProgrammer) ;
    the_programmers.push_back(new pkpProgrammer) ;
    the_programmers.push_back(new pk2Programmer) ;
    the_programmers.push_back(new pk2cmdProgrammer) ;


    // ----------------------------------------------------
    // create external tools informations
    createToolCollection() ;





    //
    // define KAction
    //
    // edition actions
    KAction *ka = 0 ;

    (KStdAction::undo(  0 , 0 , actionCollection() ,"undo" ))->setGroup("edit");

    (KStdAction::redo(  0 , 0 , actionCollection() ,"redo" ))->setGroup("edit");

    (KStdAction::cut(  0 , 0 , actionCollection() ,"cut" ))->setGroup("edit");

    (KStdAction::copy(  0 , 0 , actionCollection() ,"copy" ))->setGroup("edit");

    (KStdAction::paste(  0 , 0 , actionCollection() ,"paste" ))->setGroup("edit");

    (KStdAction::find(  0 , 0 , actionCollection() ,"find" ))->setGroup("edit");

    (new KAction(i18n("Find Next"), "pikdev_find_next"  ,
                 Qt::Key_F3, actionCollection(), "find_next"))->setGroup("edit");

    (new KAction(i18n("Find Previous"), "pikdev_find_previous" ,
                 Qt::SHIFT+Qt::Key_F3, actionCollection(), "find_previous"))->setGroup("edit");

    (KStdAction::replace(  0 , 0 , actionCollection() ,"replace" ))->setGroup("edit");

    (KStdAction::gotoLine(  0 , 0 , actionCollection() ,"goto_line" ))->setGroup("edit");
    act("goto_line")->setIcon("goto") ; // the standard gotoLine action has no icon ...

    (new KAction(i18n("Com&ment"), 0 /* no icon */ ,
                 Qt::CTRL+Qt::Key_NumberSign, actionCollection(), "comment"))->setGroup("edit");

    (new KAction(i18n("Uncomme&nt"), 0 /* no icon */,
                 Qt::CTRL+Qt::SHIFT+Qt::Key_NumberSign, actionCollection(), "uncomment"))->setGroup("edit");

    (new KAction(i18n("&Indent"), 0 /* no icon */,
                 Qt::CTRL+Qt::Key_I, actionCollection(), "indent"))->setGroup("edit");




    // file actions
    (KStdAction::openNew(  0 , 0 , actionCollection() ,"new" ))->setGroup("file");

    (KStdAction::save(  0 , 0 , actionCollection() ,"save" ))->setGroup("file");

    (KStdAction::saveAs(  0 , 0 , actionCollection() ,"save_as" ))->setGroup("file");

    (KStdAction::open(  0 , 0 , actionCollection() ,"open" ))->setGroup("file");

    KRecentFilesAction *recent_file = new   KRecentFilesAction(i18n("Open recent file..."), 0,
                                      this, SLOT(slotOpenRecentFile(const KURL &)), actionCollection(),
                                      "open_recent_file") ;
    recent_file->setGroup("file");
    recent_file->setMaxItems(20) ;

    (KStdAction::print(  0 , 0 , actionCollection(),"print_dialog"))->setGroup("file");

    (KStdAction::close(  0 , 0 , actionCollection() ,"close" ))->setGroup("file");

    (new KAction(i18n("C&lose All"), 0 /* no icon */ ,
                 Qt::CTRL+Qt::Key_L, actionCollection(), "close_all"))->setGroup("file");

    (new KAction(i18n("Save All"), "save_all" ,
                 0 , actionCollection(), "save_all"))->setGroup("file");


    (KStdAction::quit(  0 , 0 , actionCollection() ,"quit" ))->setGroup("file");

    // display actions
    (new KAction(i18n("&Split View"), "view_left_right",
                 Qt::CTRL+Qt::SHIFT+Qt::Key_L, actionCollection(), "split_view"))->setGroup("display");
    (new KAction(i18n("&Close Current View"), "view_remove",
                 Qt::CTRL+Qt::SHIFT+Qt::Key_R, actionCollection(), "remove_view"))->setGroup("display");
    (new KToggleAction(i18n("Show &Line numbers"), 0,
                       Qt::Key_F7, actionCollection(), "line_numbers"))->setGroup("display");
    (new KToggleAction(i18n("Show Icon &Border"), 0,
                       Qt::Key_F8, actionCollection(), "icon_borders"))->setGroup("display");
    (new KToggleAction(i18n("Auto Wrap Lines"), 0,
                       Qt::Key_F12, actionCollection(), "auto_wrap"))->setGroup("display");
    (new KToggleAction(i18n("Dos End Of Line"), 0,
                       0, actionCollection(), "dos_eol"))->setGroup("display");



    // project actions
    (new KAction(i18n("New..."), "pikdev_createproject" /* icone */,
                 0 /* racc clav */, actionCollection(), "new_project"))->setGroup("project");

    (new KAction(i18n("Open..."), "pikdev_openproject" /* icone */,
                 0 /* racc clav */, actionCollection(), "open_project"))->setGroup("project");

    KRecentFilesAction *recent_project = new   KRecentFilesAction(i18n("Open recent project..."), 0,
                                         this, SLOT(slotOpenRecentProject(const KURL &)), actionCollection(),
                                         "open_recent_project") ;
    recent_project->setGroup("project");
    recent_project->setMaxItems(20) ;

    (new KAction(i18n("Edit project..."), "pikdev_editproject" /* icone */,
                 0 /* racc clav */, actionCollection(), "edit_project"))->setGroup("project");

    (new KAction(i18n("Close project"), "pikdev_closeproject"  /* icone */,
                 0 /* racc clav */, actionCollection(), "close_project"))->setGroup("project");

    (new KAction(i18n("Add file..."), "pikdev_addfile"  /* icone */,
                 0 /* racc clav */, actionCollection(), "add_to_project"))->setGroup("project");

    (ka=new KAction(i18n("Add current file"), "pikdev_addcurrentfile"  /* icone */,
                    0 /* racc clav */, actionCollection(), "addcurrent_to_project"))->setGroup("project");
    // ka->setIcon("pikdev_addcurrentfile") ;

    // bookmarks actions
    (new KActionMenu(i18n("&Bookmarks"), actionCollection(), "bookmarks"))->setGroup("display");
    connect( ((KActionMenu *)act("bookmarks"))->popupMenu(), SIGNAL(aboutToShow()),this, SLOT(slotBookmarksManagement()));

    // windows actions
    (new KActionMenu(i18n("&Windows"), actionCollection(), "windows"))->setGroup("display");
    connect( ((KActionMenu *)act("windows"))->popupMenu(), SIGNAL(aboutToShow()),this, SLOT(slotWindowsMenuManagement()));

    // tools actions

    //
    // Les icones specifiques (pikdev_XXX) doivent etre dans
    // .kde/share/icons/hicolors/16x16/actions
    // et
    // .kde/share/icons/hicolors/22x22/actions
    // (ou dans le directory global, avec le meme chemin)
    //
    // a partir de kde 3.2.x, le chemin correct est
    // $prefix/share/apps/pikdev/icons/crystalsvg/16x16/actions
    // (pourquoi crystalsvg ???)
    //
    (new KAction(i18n("&Assemble"), "pikdev_compile",
                 Qt::Key_F5, actionCollection(), "assemble"))->setGroup("tools");
    connect(act("assemble"), SIGNAL(activated()),this , SLOT(assemblePrg()))  ;

    (new KAction(i18n("&Disassemble"), "pikdev_decompile",
                 Qt::Key_F5+Qt::SHIFT, actionCollection(), "deassemble"))->setGroup("tools");
    connect(act("deassemble"), SIGNAL(activated()),this , SLOT(disAssemblePrg()))  ;


    (new KAction(i18n("&Program"), "pikdev_chip",
                 Qt::Key_F6, actionCollection(), "program"))->setGroup("tools");
    connect(act("program"), SIGNAL(activated()),this , SLOT(burnChip()))  ;

    (new KAction(i18n("&Test"), 0,
                 Qt::Key_F11, actionCollection(), "test"))->setGroup("tools");
    connect(act("test"), SIGNAL(activated()),this , SLOT(testCode()))  ;

    (new KAction(i18n("Pikloops"), 0,
                 0, actionCollection(), "pikloops"))->setGroup("tools");
    connect(act("pikloops"), SIGNAL(activated()),this , SLOT(slotRunPikloops()))  ;



    // configure actions
    (new KAction(i18n("&PiKdev..."), Qt::CTRL+Qt::SHIFT+Qt::Key_P,
                 this, SLOT(slotConfigCenter()) ,
                 actionCollection(), "configure-center"))->setGroup("config");

    //    (new KAction(i18n("&Assembler..."), Qt::CTRL+Qt::SHIFT+Qt::Key_A,
    //                 this, SLOT(confAsm()) ,
    //                 actionCollection(), "configure-asm"))->setGroup("config");
    //    (new KAction(i18n("&Programmer..."), Qt::CTRL+Qt::SHIFT+Qt::Key_P,
    //                 this, SLOT(confPrg()) ,
    //                 actionCollection(), "configure-prog"))->setGroup("config");

    KAction *conf_toolbar  = KStdAction::configureToolbars(this, SLOT(slotConfigureToolbar()),actionCollection(),"configuretoolbar") ;
    conf_toolbar->setText(i18n("Toolbars...")) ;
    conf_toolbar->setShortcut( Qt::CTRL+Qt::SHIFT+Qt::Key_T) ;

    KAction *conf_edit  =new KAction(i18n("&Editor..."), Qt::CTRL+Qt::SHIFT+Qt::Key_E,
                                     this, SLOT(confEditor()) ,
                                     actionCollection(), "configure-editor");
    conf_edit->setGroup("config");
    conf_edit->setIcon("configure") ;

    setHelpMenuEnabled(true) ;


    createGUI("pikdev-main.rc") ;

    // gestion des menus dynamiques   - on recupere le menu qui vient d'etre cree
    // pour lui connecter le slot de gestion
    QPopupMenu* display = (QPopupMenu*)factory()->container("display", this);
    if( display)
    {
        connect(display,SIGNAL(aboutToShow()), this , SLOT(slotDisplayMenuManagement())) ;
    }

    //
    // close editors then leave application
    //
    connect(act("quit"), SIGNAL(activated()),  this, SLOT(exitApplication() )) ;


    // ===================================================================
    // tabs
    //
    QSplitter *splitv =  new QSplitter(this) ;
    splitv->setOrientation(Horizontal) ;
    splitv->setOpaqueResize(true) ;

    project_wid = new ProjectWid( this, splitv,"project widget") ;
    connect(act("new_project"), SIGNAL(activated()),project_wid, SLOT(slotNewProject()))  ;
    connect(act("open_project"), SIGNAL(activated()),project_wid , SLOT(slotOpenProject()))  ;
    connect(act("edit_project"), SIGNAL(activated()),project_wid , SLOT(slotEditProject()))  ;
    connect(act("close_project"), SIGNAL(activated()), project_wid, SLOT(slotCloseProject()))  ;
    connect(act("add_to_project"), SIGNAL(activated()), project_wid, SLOT(slotInsertFile()))  ;
    connect(act("addcurrent_to_project"), SIGNAL(activated()), project_wid, SLOT(slotInsertCurrentFile()))  ;

    QSplitter *splith = new QSplitter(splitv) ;
    splith->setOrientation(Vertical) ;

    edimanager = new EditorManager(splith, actionCollection()) ;

    console = new QTextEdit( splith ) ;
    console->setMinimumHeight(50) ;
    console->setTextFormat(Qt::PlainText) ;
    console->setReadOnly(true) ;

    connect(console,SIGNAL(selectionChanged()), this, SLOT(consoleClicked()) ) ;

    splith->setOpaqueResize(true) ;
    QValueList<int> sz ;
    sz+=200 ;
    sz+=30 ;
    splith->setSizes(sz) ;

    QValueList<int> szv ;
    szv+=80 ;
    szv+=350 ;
    splitv->setSizes(szv) ;

    setCentralWidget(splitv) ;
    // --------------------------------------------------------
    // status  bar
    statusBar()->setSizeGripEnabled(true)  ;
    statusBar()->message(i18n("Welcome to PiKdev."), 5000) ;
    loadConfigFile() ;

    // probe available ports before any allocation
    PrgConfigWidget::availablePorts() ;

    // get current programmer
    QString msg = updateProgrammer() ;
    //    QString type, port ;
    //    int vpp, vdd, clock, dataout, datain, datarw, clkdelay ;
    //    Config::getCurrentPortConfig(type,port, vpp,vdd,clock,dataout,datain,datarw,clkdelay );
    //    hard.setpins(type.latin1(), port.latin1() ,vpp,vdd,clock,dataout,datain,datarw,clkdelay );
    //
    //
    //    if(!hard.isok())
    //    {
    //        QMessageBox::warning(this,
    //                             i18n("Hardware configuration error"),
    //                             i18n("Cannot allocate %1 port %2.<br><br>"
    //                                  "Please&nbsp;use&nbsp;<b>Configure->Programmer</b>&nbsp;(or&nbsp;<b>CTRL+SHIFT+P</b>)<br>"
    //                                  "to setup your port configuration.").arg(type).arg(port)
    //                             , "OK") ;
    //    }
    if( msg != "")
    {
        QMessageBox::warning(this,
                             i18n("Programmer configuration error"),
                             msg
                             , "OK") ;
    }



    // once everything is properly set up, open  editors or project
    // as specified by the command line
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    for (int i = 0; i < args->count(); i++)
    {
        QString name =  args->arg(i)  ;

        if( FNU::isProjectFile(name) && project_wid->getProject() == 0)
        {  // OK, open this project
            project_wid->slotOpenProjectFile(name) ;
        }
        else if(FNU::isAsmSource(name) || FNU::isCSource(name) || FNU::isHexFile(name)
                || FNU::isIncFile(name) )
        {
            KBEditor *e = edimanager->findOrCreate(QString(args->arg(i)));

            e->slotOpen(args->url(i));
            if( FNU::isHexFile(e->fileName()))
                e->slotSetReadWrite(false) ;

        }
        // else, ignore
    }

    // now, try to reopen project/files
    // note: project or files specified with command line args
    // have precedence over previous session ones.
    QString project_name , file_name;
    QStringList file_names ;
    Config::getOpened(project_name, file_names) ;

    if( project_wid->getProject() == 0 && project_name != "")
    {
        project_wid->slotOpenProjectFile(project_name)  ;
    }

    QStringList::const_iterator p ;
    for( p = file_names.begin() ; p !=  file_names.end()  ; ++p)
    {
        if(  edimanager->findEditor(*p))
            continue ; // already open
        // verify if file exists
        KBEditor *e = edimanager->findOrCreate(*p);

        e->slotOpen(KURL(*p));
        if( FNU::isHexFile(e->fileName()) )
            e->slotSetReadWrite(false) ;
    }
    // if no filenames were given, create an empty editor
    if (edimanager->editorCount() == 0)
        edimanager->createEditor();

    // -----------------------------------------------------
    QString fullpath ;
    // test for gpasm and others
    if( !FNU::appFound("gpasm",fullpath ) || !FNU::appFound("gplink",fullpath) || !FNU::appFound("gpdasm",fullpath) )
    {
        QMessageBox::warning(this,
                             i18n("gputils installation"),
                             i18n("<b>gputils</b> package is not installed.<br><br>"
                                  "No assembler and/or no linker available.<br><br>"
                                  "Please download gputils on http://gputils.sourceforge.net"), "OK") ;

    }


    setAutoSaveSettings() ; // auto save-restore toolbars parameters and window size
}

KAction *PikMain::act(const char* name)
{
    KAction *a = actionCollection()->action(name) ;
    assert( a != 0 );

    return a ;
}

// 1 = error during file open
int PikMain::saveConfigFile()
{

    KConfig *conf = kapp->config() ;

    KRecentFilesAction *a = dynamic_cast< KRecentFilesAction *>(act("open_recent_project"))  ;
    a->saveEntries(conf, "recent-projects") ;

    a = dynamic_cast< KRecentFilesAction *>(act("open_recent_file"))  ;
    a->saveEntries(conf, "recent-files") ;

    QStringList opened_files = edimanager->getAllFileNames() ;
    QString opened_project="" ;
    Project *p = project_wid->getProject() ;
    if(p)
        opened_project = p->projectPathFileName() ;
    Config::setOpened(opened_project, opened_files) ;



    conf->sync() ;

    return 0 ;
}
//
// returns:
// 1 = error during file open
// 2 = malformed config file
int   PikMain::loadConfigFile()
{


    KConfig *conf = kapp->config() ;

    // set standard prog cards
    Config::writeStdHardwares() ;

    // set up the recent project files menu
    KRecentFilesAction *a = dynamic_cast< KRecentFilesAction *>(act("open_recent_project"))  ;
    a->loadEntries(conf, "recent-projects") ;

    a = dynamic_cast< KRecentFilesAction *>(act("open_recent_file"))  ;
    a->loadEntries(conf, "recent-files") ;

    // set toobars
    // applyMainWindowSettings(conf) ;

    return 0 ;
}

void PikMain::notImplemented()
{
    QMessageBox::warning(0,i18n("Sorry"), i18n("Not yet implemented"),
                         QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
}

void PikMain::testWidget()
{
    TestWindow *t =  new TestWindow(0) ;
    t->show() ;
}


void PikMain::assemblePrg()
{
    Project *p = project_wid->getProject() ;

    if( p == 0)
        assembleFile() ;
    else if( p->getType() == "asm" )
        assembleProject() ;
    else if( p->getType() == "C"  )
        compileCProject() ;
}

void  PikMain::assembleProject()
{
    Project *proj = project_wid->getProject() ;
    if( proj == 0)
        return  ; // security

    QStringList files = proj->getAbsFiles() ;
    QStringList::iterator i ;
    QString command = "" , x = "" ;
    console->setText("") ;

    QString expanded_include = proj->getIncludeDir() ;
    expanded_include.replace(QRegExp("\\$\\(PRJPATH\\)"), proj->projectPath() );
    expanded_include.replace(QRegExp("//"), "/" ); // strip double /
    expanded_include.replace(QRegExp("/$"), "" );  // strip trailing /com2


    int filecount ;

    // assemble specified files if needed
    for(i=files.begin(), filecount=0  ; i != files.end() ; ++i)
    {
        // save dirty buffers
        KBEditor *e = edimanager->findEditor(*i) ;
        if( e &&   e->textIsModified() )
        {
            e->slotSave() ;
            edimanager->changeToEditor(e) ;
        }

        // count files to be really Linked
        if( FNU::isAsmSource(*i) ||  FNU::isLibFile(*i) ||  FNU::isObjFile(*i) )
            ++filecount ;

        // Do not process non-source or up-to-date source files
        if( ! FNU::isAsmSource(*i) || FNU::isUpToDate(*i) )
            continue ;
        Config::getToolPath("gpasm", command) ;
        command += " -c" ;
        // -I option
        if(expanded_include != "")
        {
            command += " -I \"" ;
            command += expanded_include ;
            command += '"' ;
        }
        // -p option
        command += (" -p "+proj->getDevice()) ;
        // -r option
        x=proj->getRadix() ;
        if(x != "*" && x != "")
            command += (" -r " + x ) ;
        // -w option
        x = proj->getWarnLevel() ;
        if(x != "*" && x != "")
            command += (" -w " + x ) ;
        // misc option
        x = proj->getOtherOptions() ;
        if(x != "")
            command += ( " " + x ) ;
        // source file
        command += " \"" ;
        command += *i ;
        command += '"' ;

        QString listfile=FNU:: asmName2LstName(*i) ;
        KBEditor * lst = 0 ;
        if( executeCommand(command)!= 0)
        {
            return  ;
        }
        else   if( proj->getAsmList())     // asm OK, list needed ?
        {
            lst=  edimanager->findOrCreate(listfile) ;
            lst->slotOpen(KURL(listfile)) ;
            lst->slotSetReadWrite(false) ;
        }
        else if((lst = edimanager->findEditor(listfile)) != 0 )
        {
            edimanager->changeToEditor(lst) ;
            edimanager->removeCurrentEditor() ;
        }
    }

    if(filecount == 0)
    {
        QMessageBox::warning(0,i18n("Sorry"), i18n("Nothing to link"),
                             QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        return ;
    }

    // now, link application
    QString hexname(proj->getHexName()) ;
    Config::getToolPath("gplink", command) ;
    command += " -o \"" ;
    command += hexname  ;
    command += '"' ;

    // -a option
    x = proj->getHexFormat() ;
    if(x != "")
        command += ( " -a " + x ) ;
    // -m option
    if(proj->getLinkMap())
        command += ( " -m "  ) ;
    // -d option
    if(proj->getLinkDebug())
        command += ( " -d "  ) ;
    // -I option
    x = proj->getLibsDir() ;
    if(x != "")
        command += ( " -I \"" + x + '"' ) ;
    // -s option
    bool lnk_scr_provided = false  ;
    for( i=files.begin() ; i != files.end() ; ++i)
    {
        if( FNU::isLnkScrFile(*i) )
        {
            if( !lnk_scr_provided )
            {
                command += (" -s \"" + *i + '"') ;
                lnk_scr_provided = true ;
            }
            else
            {
                QMessageBox::warning(0,i18n("Sorry"), i18n("More than one .lkr file provided. Link aborted."),
                                     QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
                return ;
            }
        }
    }
    // misc options
    x = proj->getOtherLinkOptions() ;
    if(x != "")
        command += ( " " + x ) ;

    // object files corresponding to src files
    for( i=files.begin() ; i != files.end() ; ++i)
    {
        if( FNU::isAsmSource(*i) )
            command += (" \"" +FNU::asmName2ObjName(*i) + '"' ) ;
    }
    // pre assembled objects
    for( i=files.begin() ; i != files.end() ; ++i)
    {
        if( FNU::isObjFile(*i) )
            command += (" \"" + *i + '"') ;
    }
    // libs must be at the end of the command
    for( i=files.begin() ; i != files.end() ; ++i)
    {
        if( FNU::isLibFile(*i) )
            command += (" \"" + *i + '"') ;
    }
    if( executeCommand(command) == 0)
    {          // open the corresponding hex read-only editor
        KBEditor *hex = edimanager->findOrCreate(hexname) ;
        // read hex file
        hex->slotOpen(KURL(hexname)) ;
        hex->slotSetReadWrite(false) ;
        // if map requested, also open the map file
        KBEditor *map   ;
        QString mapfile = FNU::changeExt( proj-> projectPathFileName(), "map")  ;
        if( proj->getLinkMap())
        {
            map =  edimanager->findOrCreate(mapfile) ;
            map->slotOpen(KURL(mapfile)) ;
            map->slotSetReadWrite(false) ;
        }
        else if((map = edimanager->findEditor(mapfile)) != 0 )
        {
            edimanager->changeToEditor(map) ;
            edimanager->removeCurrentEditor() ;
        }
    }
}

void PikMain::assembleFile()
{

    QString txt , includedirs, others, warnlevel, proc, hexformat, radix ;
    ;
    int status ;
    KBEditor *e = edimanager->currentEditor() ;

    Config::getAsmConfig(proc,hexformat,includedirs,radix,warnlevel,others) ;

    if( e != 0 )
    {
        if( !FNU::isAsmSource(e->filePathName()) )
        {
            QMessageBox::warning(0,"Sorry",
                                 i18n("Current buffer is not an asm source file"),
                                 QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
            return ;

        }
        if( e->textIsModified() )
        {
            e->slotSave() ;  // buffer is now systematically saved
        }

        // expension of $(SRCPATH) in includedirs
        QString expanded_includedirs = includedirs ;
        expanded_includedirs.replace(QRegExp("\\$\\(SRCPATH\\)"), e->pathName() );
        // eventually remove //
        expanded_includedirs.replace(QRegExp("//"), "/" );
        // and in others sub-command
        QString expanded_others = others ;
        expanded_others.replace(QRegExp("\\$\\(SRCPATH\\)"), e->pathName() );
        // eventually remove //
        expanded_others.replace(QRegExp("//"), "/" );



        console->setText("") ;
        QString hexname = FNU::asmName2HexName(e->filePathName()) ;
        QString command ;
	Config::getToolPath("gpasm", command) ;
	command += " -L -o " ;

        command += '"' ;

        command += hexname  ;
        command += '"'  ;
        // parameter == * means that assembler must use hard-coded directive
        // provided by the source file.
        if(warnlevel != "*")
            command += " -w " , command += warnlevel ;
        if( expanded_includedirs != "")
            command += " -I \"" ,command += expanded_includedirs, command += '"' ;
        if(proc != "*")
            command += " -p " , command += proc ;
        if(hexformat != "*")
            command += " -a " , command += hexformat ;
        if(radix != "*")
            command += " -r " , command += radix;
        if(expanded_others != "")
            command += " " , command += expanded_others ;
        command += " \"" ;
        command += e->filePathName() ;
        command += '"' ;

        status = executeCommand(command) ;
        if( status == 0)     // no problem
        {
            // open the corresponding list read-only editor
            QString lstname = FNU::asmName2LstName(e->filePathName()) ;
            if( lstname != "")
            {
                KBEditor *lst = edimanager->findOrCreate(lstname) ;
                // read list file
                lst->slotOpen(KURL(lstname)) ;
                lst->slotSetReadWrite(false) ;
            }

            // open the corresponding hex read-only editor
            QString hexname = FNU::asmName2HexName(e->filePathName()) ;
            if( hexname != "")
            {
                KBEditor *hex = edimanager->findOrCreate(hexname) ;
                // read hex file
                hex->slotOpen(KURL(hexname)) ;
                hex->slotSetReadWrite(false) ;
            }
        }
    }
}

void PikMain::burnChip()
{
    // some persons want to burn chips without
    // having correctly configured port

    if( current_programmer == 0)
    {
        QMessageBox::warning(0,i18n("Sorry"),
                             i18n("No programmer available."),
                             QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        return ;
    }

    if( !current_programmer->connectionOK()  )
    {
        KMessageBox::detailedSorry(this,
                             i18n("Hardware port not available"),
				i18n(
                                  "<b>Parallel&nbsp;port</b>&nbsp;(/dev/parport0,/dev/parports/0,etc.)<br>"
                                  "or<br>"
                                  "<b>Serial port</b>&nbsp;(/dev/ttyS0,/dev/ttyS1,etc.)<br>"
                                  "must exist and must be RW enabled.<br><br>"
                                  "See http://pikdev.free.fr for details.") ) ;
        return ;
    }

    if( project_wid->getProject() )
        burnChipProject() ;
    else
        burnChipFile() ;
}
/**
  Calls the programmer widget for the currently open project
*/

void PikMain::burnChipProject()
{
    Project * proj =  project_wid->getProject() ;
    if( proj == 0)
        return ; // Mmmmm

    QString hexfile = proj->getHexName() ;
    QString device = proj->getDevice() ;

    if( !current_programmer->selectDevice(device) )
    {
        QMessageBox::warning(0,i18n("Sorry"),
                             i18n("This pic device is not supported (%1).").arg(device),
                             QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        return ;
    }
    //
    // try to open  hex file
    //
    const char * txt = current_programmer->device()->loadHexFile(hexfile);
    if( txt != 0  )
    {
        QString mess( i18n("Loading problem on <b>%1</b>: %2 "
                           "<br><br>Do you want to open the programming window anyway?").arg(hexfile).arg(txt)) ;
        if( QMessageBox::warning(0,i18n("Sorry"), mess  ,
                                 QMessageBox::Yes, QMessageBox::No, QMessageBox::NoButton) == QMessageBox::No)
            return ;
    }
    programmerFile = hexfile ; // OK

    if( programmer_widget != 0)
    {
        // A programmer is still active : close it and reopen a new one
        programmer_widget->close(true) ;
        programmer_widget = 0 ;
    }

    programmer_widget = new PrgWid( current_programmer ,programmerFile,0) ;
    // connect programmer's messages to console
    connect(programmer_widget,SIGNAL(messageGenerated(QString&)),
            this,SLOT(displayMessage(QString&))) ;
    // proper signaling of programmer close
    connect(programmer_widget,SIGNAL(destroyed()),
            this,SLOT(programmerClosed())) ;
    connect(programmer_widget,SIGNAL(fileUpdated(const QString&)),
            this,SLOT(slotShowHex(const QString&))) ;

    programmer_widget->go() ;
}
/**
  Calls the programmer widget for the currently open hex file
*/
void PikMain::burnChipFile()
{
    QString   proc,hexformat,includedirs,radix,warnlevel,others  ;

    Config::getAsmConfig(proc,hexformat,includedirs,radix,warnlevel,others) ;
    //
    // if an hex file is open, get it as the default data
    // to be programmed
    //
    KBEditor *e = edimanager->currentEditor() ;
    if( e == 0)
    {
        QMessageBox::warning(0,i18n("Sorry"),
                             i18n("No buffer available." )
                             ,
                             QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        return ;
    }
    QString filename ;
    //
    // find the target pic flavor
    //
    // try with the name specifed in the asm configuration Widget
    QString device(proc) ;

    if( !current_programmer->selectDevice(device) )
    {
        // the device name is perhaps not specified,
        // try to parse the source file to obtain it.
        filename =  e->filePathName()  ;
        if(FNU::isHexFile(filename)  )
        {
            filename = FNU::hexName2AsmName(filename) ;
            snifDeviceName(filename, device) ;

            if(!current_programmer->selectDevice(device) ) // try .ASM extension    GRRRRR
            {
                filename = FNU::changeExt(filename,"ASM") ;
                snifDeviceName(filename, device) ;     // last chance to get a device type ..
                current_programmer->selectDevice(device) ;
            }
        }
    }
    if( current_programmer->device() == 0)
    {
        if( device != "*")
        {
            QMessageBox::warning(0,i18n("Sorry"),
                                 i18n("This pic device  is not supported  (%1).").arg(device),
                                 QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        }
        else
        {
            QMessageBox::warning(0,i18n("Sorry"),
                                 i18n("Target device is not configured and cannot be guessed by source code analysis<br><br>"
                                      "Possible causes:<br><br>-The current buffer is not an hex file,"
                                      "<br>-The corresponding source file cannot be found,"
                                      "<br>-This source file does not contain any processor directive." )
                                 ,
                                 QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        }
        return ;
    }

    //
    // try to open the hex file
    //
    if( e != 0 && FNU::isHexFile(e->filePathName()) )
    {
        filename = e->filePathName()  ;
        const char * txt = current_programmer->device()->loadHexFile(filename);

        if( txt != 0  )
        {
            QMessageBox::warning(0,i18n("Sorry"), txt + filename  ,
                                 QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
            return ;
        }
        programmerFile = filename ; // OK
    }

    if( programmer_widget != 0)
    {
        // A programmer is still active : close it and open a new one
        programmer_widget->close(true) ;
        programmer_widget = 0 ;
    }




    programmer_widget = new PrgWid(current_programmer,programmerFile,0) ;
    // connect programmer  messages to console
    connect(programmer_widget,SIGNAL(messageGenerated(QString&)),
            this,SLOT(displayMessage(QString&))) ;
    // signaling  programmer close
    connect(programmer_widget,SIGNAL(destroyed()),
            this,SLOT(programmerClosed())) ;
    // signaling writing file
    connect(programmer_widget,SIGNAL(fileUpdated(const QString&)),
            this,SLOT(slotShowHex(const QString&))) ;

    programmer_widget->go() ;
}

void PikMain::displayMessage(QString& txt)
{
    console->setText(txt) ;
}
//
// Traite les clics de l'utilisateur dans la console texte
//
void PikMain::consoleClicked()
{
    int p1, i1 ;
    console->getCursorPosition(&p1,&i1) ;
    QString txt(console->text(p1))  ;
    // static QRegExp r("^([^:]*):([0-9]+):([^:]*)$") ;
    static QRegExp r("^([^:]*):([0-9]+):.*$") ;
    r.search(txt) ;

    QStringList list = r.capturedTexts() ;

    if( list.count() == 3 )
    {
        QString ln = list[2] ;
        if(!ln.isNull())
        {
            int nn = ln.toInt() - 1 ;

            KBEditor *e =  edimanager->switchToEditor(list[1]) ;

            if( e != 0 && e->selectLine(nn) )
            {
                QTimer::singleShot(10,e,SLOT(slotSelectLine()));
                QTimer::singleShot(200,e,SLOT(slotUnSelectLine()));
            }
        }
    }
}

void PikMain::programmerClosed()
{
    programmer_widget = 0 ;
}

void PikMain::exitApplication()
{
    saveConfigFile() ;

    edimanager->closeAllFiles();

    if( programmer_widget)
        programmer_widget->queryClose();
    qApp->quit()  ;
}

void  PikMain::slotDisplayMenuManagement()
{
    KBEditor *e = edimanager->currentEditor() ;
    if(e)
    {

        KToggleAction *kt = dynamic_cast<KToggleAction *>(act("line_numbers")) ;
        if(kt)
            kt->setChecked( e->lineNumbersOn() ) ;
        kt = dynamic_cast<KToggleAction *>(act("icon_borders")) ;
        if(kt)
            kt->setChecked( e->borderOn() ) ;
        kt = dynamic_cast<KToggleAction *>(act("auto_wrap")) ;
        if(kt)
            kt->setChecked( e->wrapOn() ) ;
        kt = dynamic_cast<KToggleAction *>(act("dos_eol")) ;
        if(kt)
            kt->setChecked( e->dosEOLOn() ) ;

    }
}

void  PikMain::slotBookmarksManagement()
{
    KBEditor *e = edimanager->currentEditor() ;
    if(e)
    {
        e->updateBookmarksMenu(((KActionMenu *)act("bookmarks"))->popupMenu()) ;
    }
}
/** No descriptions */
void PikMain::slotConfigureToolbar()
{
    saveMainWindowSettings( KGlobal::config(), "MainWindow" );
    KEditToolbar dlg(actionCollection(),"pikdev-main.rc",false, 0,"Main window Toolbar Editor") ;
    connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(slotApplyToolbarSettings()));
    if(dlg.exec() )
        createGUI("pikdev-main.rc")	;
}
/** No descriptions */
void PikMain::slotApplyToolbarSettings()
{
    applyMainWindowSettings(KGlobal::config(), "MainWindow") ;
}
/** Parse a source file to find which device has to be programmed.
 
\param device The returned divice name (may be empty)
\return 
1 == OK
0 == file not found
*/

int PikMain::snifDeviceName(const QString& sourcefilename, QString& device)
{
    QFile f(sourcefilename) ;
    int k ;
    if( !f.open( IO_ReadOnly ))
        return 0 ;

    device = "" ;
    QString line ;
    //   QRegExp re1("^[ \\t]+(?:PROCESSOR|processor)[ \\t]+((?:p|sx|P|SX)[a-z0-9A-Z]+)" ) ;
    QRegExp re1("^[ \\t]+(?:PROCESSOR|processor)[ \\t]+([a-z0-9A-Z]+)" ) ;
    QRegExp re2("^[ \\t]+(?:LIST|list)[ \\t]+" ) ;
    while( f.readLine(line, 10000) != -1)
    {
        // search PROCESSOR directive
        if(re1.search(line,0) != -1)
        {
            device = re1.cap(1) ;
            break;
        }
        // search LIST p=... directive
        if((k=re2.search(line,0)) != -1)
        {
            //QRegExp re3("(?:p|P)[ \\t]*=[ \\t]*((?:p|sx|P|SX)[a-z0-9A-Z]+)") ;
            QRegExp re3("(?:p|P)[ \\t]*=[ \\t]*([a-z0-9A-Z]+)") ;
            if( re3.search(line,k+5) != -1)
            {
                device = re3.cap(1) ;
                break;
            }
        }
    }
    // performs some magics to make device name gpasm conformant.
    device = device.lower() ;
    if( device != "" && device[0] != 'p')
        device = "p"+device ; // add p prefix if missing
    return  1 ;
}
/** Test stub */
void PikMain::testCode()
{
    new ConfigCenter(this) ;
}
/** Write a command to console, and execute it.
Error messages are written back to the console with red ink
\return satus of the executed command
 */
int PikMain::executeCommand(const QString& command)
{
    FILE *f ;
    int status = -1 ;
    static QRegExp asm_error ("^([^:]*):([0-9]+):([^:]*)$") ;
    static QRegExp link_error ("^error:.*$") ;
    static QRegExp link_debug ("^debug:.*$") ;
    static QRegExp link_info ("^message:.*$") ;
    static QRegExp C_error("^.*:([0-9]+): error:.*$") ;
    static QRegExp C_warning("^.*:([0-9]+): warning:.*$") ;
    static QRegExp CPP_error("^.*:([0-9]+):([0-9]+):.*:.*$") ;
    QColor color ;

    console->append( command+"\n" ) ;
    f = popen((command + " 2>&1").latin1(),"r") ;
    if( f != 0)
    {
        char t[512] ;
        while(fgets(t,511,f) == t)
        {
            if( asm_error.search(t) != -1 || C_error.search(t) != -1 || CPP_error.search(t) != -1 )
                color.setRgb(255,0,0) ;   //  ASM or C error   (RED)
            else if( C_warning.search(t) != -1)
                color.setRgb(0xFF, 0x60, 0x2F) ;  //  C warning   (ORANGE RED)
            else if( link_error.search(t) != -1)
                color.setRgb(180 ,0,0) ;  //  GPLINK error   (DARK RED)
            else if( link_debug.search(t) != -1)
                color.setRgb(0,0,255) ;   //  GPLINK debug (BLUE)
            else if( link_info.search(t) != -1)
                color.setRgb(0,160,0) ;   //  GPLINK information  (DARK GREEN)
            else
                color.setRgb(0,0,0 )  ;   //  other   (BLACK)
            console->setColor(color);
            console->append(t)  ;
            console->setColor(QColor(0,0,0) );
        }
        status = pclose(f);
        if( status != 0)
        {
            console->append(i18n("Error code: %1\n").arg(status)  ) ;
        }
    }
    else
    {
        console->append(i18n("Cannot execute [%1]").arg(command)) ;
    }
    return status ;
}
/** Accessor for the project widget */
ProjectWid *PikMain::projectWid()
{
    return project_wid ;
}
/** Accessor for the editors manager */
EditorManager *PikMain::editorManager()
{
    return edimanager ;
}
/** No descriptions */
void PikMain::slotOpenRecentProject(const KURL &url)
{
    project_wid->slotOpenProjectFile(url.directory(false)+url.fileName() ) ;
}
/** No descriptions */
void PikMain::slotOpenRecentFile(const KURL &url)
{
    edimanager->slotOpenFile(url) ;
}
/** No descriptions */
void PikMain::disAssemblePrg()
{
    QString proc, other_opt ;
    bool short_format ;

    int status ;
    KBEditor *e = edimanager->currentEditor() ;

    Config::getDAsmConfig(proc,short_format,other_opt) ;

    // in project mode, we use the project target device
    if( project_wid->getProject() )
        proc =  project_wid->getProject()->getDevice() ;

    if( e != 0 )
    {
        if( !FNU::isHexFile(e->filePathName()) )
        {
            QMessageBox::warning(0,"Sorry",
                                 i18n("Current buffer is not an hex file"),
                                 QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
            return ;

        }

        console->setText("") ;
        QString hexname = e->filePathName() ;
        // file name xxx.hex => xxx.hex.asm
        QString outname = hexname + ".asm"  ;
        QString command ;
        Config::getToolPath("gpdasm", command) ;
        command += " -p " ;
        command += proc ;
        command += ' ' ;
        if( short_format )
            command += "-s " ;
        command += hexname  ;
        command += " >" ;
        command += outname ;

        status = executeCommand(command) ;
        if( status == 0)     // no problem
        {
            // open the corresponding  editor
            if( outname != "")
            {
                KBEditor *lst = edimanager->findOrCreate(outname) ;
                // read src file
                lst->slotOpen(KURL(outname)) ;
            }
        }
    }
}


void PikMain::slotShowHex(const QString& fname)
{
    KBEditor *e = edimanager->findOrCreate(fname);

    if(e)
    {
        e->slotOpen(fname);
        console->setText("") ;
        console->setColor(QColor (0,160,0)) ;
        console->append(i18n("File %1 have been reloaded from disk.").arg(fname)) ;
        console->setColor(QColor (0,0,0)) ;
    }
}
/** No descriptions */
void PikMain::confEditor()
{
    KBEditor *e = edimanager->currentEditor() ;
    if( e)
        e->slotConfigEditor() ;
}
/** Try to   run the pikloops
code generator for delays */
void PikMain::slotRunPikloops()
{
    QString fullpath ;
    Config::getToolPath("pikloops", fullpath) ;
    if( fullpath != "")
    {
        fullpath += " 2>&1 &" ;
        FILE *f = popen(fullpath.latin1() ,"r") ;
        pclose(f);
    }
    else
    {
        KMessageBox::detailedSorry( this,  i18n("Cannot run Pikloops"),
                                    i18n("The Pikloops utility is not installed:"
                                         " please contact Javier Fernando Vargas (fernandovargas@cable.net.co)"
                                         " to obtain it.\n"
                                         " You also can download pikloops at http://pikdev.free.fr"  )) ;
    }
}
/** Perform clean up BEFORE the window is closed.
 */
bool PikMain::queryClose()
{
    exitApplication() ;
    return true ;
}
/** No descriptions */
void PikMain::slotConfigCenter()
{
    if( config_center == 0 )
    {
        config_center = new ConfigCenter(this) ;
        connect( config_center, SIGNAL(destroyed()), this, SLOT(slotConfigCenterClosed())) ;
    }
}
/** No descriptions */
void PikMain::slotConfigCenterClosed()
{
    config_center = 0 ;
}
/** No descriptions */
void PikMain::compileCProject()
{
    Project *proj = project_wid->getProject() ;
    if( proj == 0)
        return  ; // security

    KBEditor * finalsrc, *list ;

    QStringList files = proj->getAbsFiles() ;
    QStringList::iterator i ;
    QString command = "" , x = "" ;
    console->setText("") ;

    QString expanded_include = proj->getCIncludeDir() ;
    expanded_include.replace(QRegExp("\\$\\(PRJPATH\\)"), proj->projectPath() );
    expanded_include.replace(QRegExp("//"), "/" ); // strip double /
    expanded_include.replace(QRegExp("/$"), "" );  // strip trailing /

    QString expanded_libs = proj->getCLibsDir() ;
    expanded_libs.replace(QRegExp("\\$\\(PRJPATH\\)"), proj->projectPath() );
    expanded_libs.replace(QRegExp("//"), "/" ); // strip double /
    expanded_libs.replace(QRegExp("/$"), "" );  // strip trailing /

    QString compiler = proj->getCCompiler() ;

    if( compiler != "cpik")
    {

        QMessageBox::warning(0,i18n("Sorry"),
                             i18n("PiKdev currently only supports 'cpik'\n"
                                  "C compiler for pic 18 devices"),
                             QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;

        return ;
    }


    int filecount ;

    // ------------------------------------------- COMPILE
    // Compile specified files if needed
    for(i=files.begin(), filecount=0  ; i != files.end() ; ++i)
    {
        // save dirty buffers
        KBEditor *e = edimanager->findEditor(*i) ;
        if( e &&   e->textIsModified() )
        {
            e->slotSave() ;
            edimanager->changeToEditor(e) ;
        }



        // count files to be really Linked
        if( FNU::isAsmSource(*i) ||  FNU::isSrcLib(*i) ||  FNU::isCSource(*i) )
            ++filecount ;

        // Do not process non-source
        if( ! FNU::isCSource(*i)  )
            continue ;

        Config::getToolPath("cpik", command) ;
        command += " -c" ;
        // -I option

        if(expanded_include != "")
        {
            command += " -I \"" ;
            command += expanded_include ;
            command += '"' ;
        }

        // -p option
        command += (" -p "+proj->getDevice()) ;

        // misc option
        x = proj->getOtherCOptions() ;
        if(x != "")
            command += ( " " + x ) ;
        // source file
        command += " \"" ;
        command += *i ;
        command += '"' ;

        QString slbfile=FNU:: CName2SlbName(*i) ;
        KBEditor * slb = 0 ;
        if( executeCommand(command)!= 0)
        {
            return  ;
        }

        if( proj->getCSlb() )     // .slb files needed ?
        {
            slb=  edimanager->findOrCreate(slbfile) ;
            slb->slotOpen(KURL(slbfile)) ;
            slb->slotSetReadWrite(false) ;
        }
        else
            removeEditor(slbfile) ;

    }

    if(filecount == 0)
    {
        QMessageBox::warning(0,i18n("Sorry"), i18n("Nothing to link"),
                             QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton) ;
        return ;
    }

    // -------------------------------------------- LINK
    // now, link application
    QString asmname(proj->getAsmName()) ;
    Config::getToolPath("cpik",  command) ;
    command += " -o \"" ;
    command += asmname  ;
    command += '"' ;

    command += (" -p "+proj->getDevice()) ;

    // misc options
    x = proj->getOtherLinkOptions() ;
    if(x != "")
        command += ( " " + x ) ;

    // object files correspnding to src files
    for( i=files.begin() ; i != files.end() ; ++i)
    {
        if( FNU::isCSource(*i) )
            command += (" \"" +FNU::CName2SlbName(*i) + '"' ) ;
    }
    // pre compiled asm or slb
    for( i=files.begin() ; i != files.end() ; ++i)
    {
        if(FNU::isSrcLib(*i) || FNU::isAsmSource(*i) )
            command += (" \"" + *i + '"') ;
    }

    if( expanded_libs != "")
    {
        command += " -L " ;
        command += ('"' + expanded_libs + '"') ;
    }


    if( executeCommand(command) == 0 )
    {
        if( proj->getCAsm())
        {
            // open the corresponding  editor
            finalsrc = edimanager->findOrCreate(asmname) ;
            // read final asm file
            finalsrc->slotOpen(KURL(asmname)) ;
            finalsrc->slotSetReadWrite(true) ;  // provisoire
        }
        else
            removeEditor(asmname) ;
    }
    else
        return ;
    // --------------------------------------------- ASSEMBLE SINGLE FILE

    expanded_include = proj->getIncludeDir() ;
    expanded_include.replace(QRegExp("\\$\\(PRJPATH\\)"), proj->projectPath() );
    expanded_include.replace(QRegExp("//"), "/" ); // strip double /
    expanded_include.replace(QRegExp("/$"), "" );  // strip trailing /com2

    QString hexname(proj->getHexName())   ;

    Config::getToolPath("gpasm", command) ;
    command += " -L -o " ;
    command += " \"" ;
    command += hexname ;
    command += " \"" ;

    // -I option
    if(expanded_include != "")
    {
        command += " -I \"" ;
        command += expanded_include ;
        command += '"' ;
    }
    // -w option
    x = proj->getWarnLevel() ;
    if(x != "*" && x != "")
        command += (" -w " + x ) ;


    // misc option
    x = proj->getOtherOptions() ;
    if(x != "")
        command += ( " " + x ) ;
    // source file
    command += " \"" ;
    command += asmname ;
    command += '"' ;

    if( executeCommand(command) == 0)
    {
        // open the corresponding  editor
        KBEditor *hex = edimanager->findOrCreate(hexname) ;
        // read final asm file
        hex->slotOpen(KURL(hexname)) ;
        hex->slotSetReadWrite(false) ;

        QString listname = FNU::asmName2LstName(asmname)  ;
        if(proj->getAsmList())
        {
            list = edimanager->findOrCreate(listname) ;
            // read final asm file
            list->slotOpen(KURL(listname)) ;
            list->slotSetReadWrite(false) ;
        }
        else
            removeEditor(listname) ;
    }
}
/** No descriptions */
void PikMain::removeEditor(const QString& name)
{
    KBEditor *k = edimanager->findEditor(name) ;
    if(k)
    {
        edimanager->changeToEditor(k) ;
        edimanager->removeCurrentEditor() ;
    }
}
/** No descriptions */
void PikMain::slotWindowsMenuManagement()
{

    KPopupMenu *pop =  ((KActionMenu *)act("windows"))->popupMenu()  ;

    pop->clear ();

    QPtrList<KBEditor>& edits = edimanager->getEditors() ;
    KBEditor *e ;
    int i ;


    for (i= 0, e = edits.first() ; e ; e = edits.next() , ++i)
    {
        QString name = e->fileName() ;
        if( name.isEmpty() )
            name = i18n("<no name>") ;
        pop->insertItem ( name , this, SLOT(slotRaiseWindow(int)), 0  , i );
        if( e == edimanager->currentEditor())
            pop->setItemChecked(i, true ) ;
    }
}
/** No descriptions */
void PikMain::slotRaiseWindow(int n)
{
    QPtrList<KBEditor>& edits = edimanager->getEditors() ;
    KBEditor *e = edits.at(n) ;
    if(e)
        edimanager->changeToEditor(e) ;
}
/** No descriptions */
QValueVector<ProgrammerBase *>& PikMain::programmersList()
{
    return the_programmers ;
}
/** Remove  current programmer and replace it by programmer specifed by config*/
QString PikMain::updateProgrammer()
{
    QString progname ;
    Config::getCurrentProgrammer( progname ) ;
    unsigned int np ;

    for(np = 0 ; np < the_programmers.size() ; ++np)
    {
        if( the_programmers[np]->shortName() == progname)
        {
            // before changing  programmer, be sure
            // that programmer widget is closed
            if( programmer_widget)
            {
                programmer_widget->close(true) ;
                programmer_widget = 0 ;
            }
            // if a programmer already installed, remove it
            if( current_programmer != 0)
            {
                current_programmer->exit() ;
            }
            current_programmer = the_programmers[np]   ;

            return current_programmer->enter() ;
        }
    }
    return i18n("PikMain::updateProgrammer() - internal error, programmer [%1] not found").arg(progname) ;
}
//
// ask gpasm for valid processors
//
QStringList PikMain::getProcList()
{

    QStringList  supported_procs = current_programmer->devices() ;
    QString comm ;
    Config::getToolPath("gpasm", comm) ;
    comm += " -l 2>&1" ;

    FILE *f = popen(comm.latin1(), "r") ;
    char name[60] ;
    QStringList list ;

    if( current_programmer )
    {
        if( f != 0)
        {
            while(fscanf(f,"%59s", name) != EOF)
            {
                if(*name == 'p')  // get pic names only
                {
                    QString qname(name) ;

                    if(supported_procs.findIndex(qname) != -1)
                        qname += " (P)" ;

                    list += qname ;
                }
            }

            pclose(f) ;
        }
        else
            list += "" ;
    }
    else
        list += "" ;
    return list ;
}
/** No descriptions */
QStringList PikMain::getDProcList()
{
    QStringList list ;
    QString comm ;
    Config::getToolPath("gpdasm", comm) ;
    if( comm != "")
    {
        comm += " -l 2>&1" ;
        FILE *f = popen(comm.latin1(), "r") ;
        char name[60] ;

        if( f != 0)
        {
            while(fscanf(f,"%59s", name) != EOF)
            {
                if( *name == 'p')
                    list += name ;
            }
            pclose(f) ;
        }
    }
    if( list.empty() )
        list += "" ;
    return list ;
}



/*!
    \fn PikMain::getConsole()
 */
QTextEdit * PikMain::getConsole()
{
    return console ;
}


/*!
    \fn PikMain::createToolCollection()
 */
void PikMain::createToolCollection()
{
    // empty tool list

    Config::removeToolList() ;

    Config::createToolEntry
    ("gpasm",
     i18n("gpasm is an assembler for PIC microcontrollers.\nIt is required by PiKdev to develop any application and is part of the gputils suite."), "http://gputils.sourceforge.net/" ,
     true) ;

    Config::createToolEntry
    ("gpdasm",
     i18n("gpasm is a disassembler for PIC microcontrollers.\nIt is recommended by PiKdev and is part of the gputils suite."), "http://gputils.sourceforge.net/" ,
     true) ;

    Config::createToolEntry
    ("gplink",
     i18n("gpasm is a linker for PIC microcontrollers.\nIt is required by PiKdev to develop any application and is part of the gputils suite."), "http://gputils.sourceforge.net/" ,
     true) ;

    Config::createToolEntry
    ("pikloops",
     i18n("pikloops is a tool for automatic generation of accurate delay routines.\nJust drag generated code to PiKdev editor."),"http://pikloops.tripod.com/" ,
     false) ;

    Config::createToolEntry
    ("astyle",
     i18n("astyle performs automatic indentation of C source code.\nYou only need it if you develop C programs with PiKdev."),"http://sourceforge.net/projects/astyle" ,
     false) ;

    Config::createToolEntry
    ("cpik",
     i18n("cpik is a C compiler for pic18Fxxx devices.\ncpik is fully interfaced with PiKdev."),
     "http://pikdev.free.fr" ,
     false) ;

    Config::createToolEntry
    ("pk2",
     i18n("pk2 is a programming software for USB PICKit2 programmers from Microchip."),
     "http://home.pacbell.net/theposts/picmicro/" ,
     false) ;

    Config::createToolEntry
    ("pk2cmd",
     i18n("pk2cmd is a programming software for USB PICKit2 programmers from Microchip. pk2cmd is a replacement for pk2."),
     "http://www.microchip.com" ,
     false) ;

    Config::createToolEntry
    ("pkp",
     i18n("pkp is a command line programmer which uses PiKdev programming engine.\nJust included here for development purpose."),
     "http://pikdev.free.fr" ,
     false) ;
}
