/***************************************************************************
 *   Copyright (C) 2012 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#include <QWidget>
#include <QTabWidget>
#include <QTabBar>
#include <QToolBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QMimeData>
#include <QGridLayout>
#include <QSplitter>
#include <QToolButton>
#include <QSettings>

#include "editorwidget.h"
#include "findreplace.h"
#include "propdialog.h"
#include "scrollbar.h"
#include "basedebugger.h"
#include "mainwindow.h"
#include "simulator.h"
#include "thememanager.h"
#include "utils.h"

#include "intprop.h"
#include "boolprop.h"

EditorWidget::EditorWidget( QWidget* parent )
            : QWidget( parent )
            , CompBase( "Editor", "" )
            , m_outPane( this )
            , m_settingsMenu( this )
            , m_fileMenu( this )
{
    setAcceptDrops( true ); 

    createActions(); 
    createToolBars(); 
    createWidgets(); 
    updateRecentFileActions(); 
    readSettings(); 

    addPropGroup( { tr("Editor Settings"), {
        new IntProp <EditorWidget>("FontSize", tr("Font Size"),"_px"
                                  , this,&EditorWidget::fontSize, &EditorWidget::setFontSize, 0 ),

        new IntProp <EditorWidget>("TabSize", tr("Tab Size"),""
                                  , this, &EditorWidget::tabSize, &EditorWidget::setTabSize, 0 ),

        new BoolProp<EditorWidget>("SpaceTabs", tr("Tabs as spaces"),""
                                  , this, &EditorWidget::spaceTabs, &EditorWidget::setSpaceTabs ),

        new BoolProp<EditorWidget>("ShowSpaces", tr("Show Spaces and Tabs"),""
                                  , this, &EditorWidget::showSpaces, &EditorWidget::setShowSpaces ),

        new ComProperty("", tr("Auto close pairs:"),"","",0),

        new BoolProp<EditorWidget>("CloseParenthesis", tr("Auto close Parenthesis ( )"),""
                                  , this, &EditorWidget::closeParenthesis, &EditorWidget::setCloseParenthesis ),

        new BoolProp<EditorWidget>("CloseBraces", tr("Auto close Braces { }"),""
                                  , this, &EditorWidget::closeBraces, &EditorWidget::setCloseBraces ),

        new BoolProp<EditorWidget>("CloseBrackets", tr("Auto close Brackets [ ]"),""
                                  , this, &EditorWidget::closeBrackets, &EditorWidget::setCloseBrackets ),

        new BoolProp<EditorWidget>("CloseQuotes", tr("Auto close Quotes \" \""),""
                                  , this, &EditorWidget::closeQuotes, &EditorWidget::setCloseQuotes ),

        new BoolProp<EditorWidget>("CloseSquotes", tr("Auto close Single Quotes ' '"),""
                                  , this, &EditorWidget::closeSquotes, &EditorWidget::setCloseSquotes ),
    }, 0} ); 
}
EditorWidget::~EditorWidget(){}

void EditorWidget::setFontSize( int size )
{
    m_fontSize = size; 
    m_font.setPixelSize( size ); 
    MainWindow::self()->settings()->setValue( "Editor_font_size", QString::number(m_fontSize) ); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setFont( m_font ); 

    setTabSize( m_tabSize ); 
}

void EditorWidget::setTabSize( int size )
{
    m_tabSize = size; 
    MainWindow::self()->settings()->setValue( "Editor_tab_size", QString::number(m_tabSize) ); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setTabStopDistance( calcTabstopWidth() ); 
}

void EditorWidget::setShowSpaces( bool show )
{
    m_showSpaces = show; 

    for( CodeEditor* ce : getCodeEditors() ) docShowSpaces( ce ); 

    QString showStr = m_showSpaces ? "true" : "false"; 
    MainWindow::self()->settings()->setValue( "Editor_show_spaces", showStr ); 
}

void EditorWidget::docShowSpaces( CodeEditor* ce )
{
    QTextOption option = ce->document()->defaultTextOption(); 

    if( m_showSpaces ) option.setFlags( option.flags() | QTextOption::ShowTabsAndSpaces  ); 
    else               option.setFlags( option.flags() & ~QTextOption::ShowTabsAndSpaces ); 

    ce->document()->setDefaultTextOption( option ); 
}

void EditorWidget::setSpaceTabs( bool on )
{
    m_spaceTabs = on; 

    if( on ) { m_tab = "";  for( int i=0;  i<m_tabSize;  i++) m_tab += " ";  }
    else m_tab = "\t"; 

    if( m_spaceTabs )
         MainWindow::self()->settings()->setValue( "Editor_spaces_tabs", "true" ); 
    else MainWindow::self()->settings()->setValue( "Editor_spaces_tabs", "false" ); 
}

void EditorWidget::setCloseParenthesis( bool c )
{
    if( c ) m_autoClose |= 1<<0; 
    else    m_autoClose &= ~(1<<0); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setAutoClose( m_autoClose ); 
}

void EditorWidget::setCloseBraces( bool c )
{
    if( c ) m_autoClose |= 1<<1; 
    else    m_autoClose &= ~(1<<1); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setAutoClose( m_autoClose ); 
}

void EditorWidget::setCloseBrackets( bool c )
{
    if( c ) m_autoClose |= 1<<2; 
    else    m_autoClose &= ~(1<<2); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setAutoClose( m_autoClose ); 
}

void EditorWidget::setCloseQuotes( bool c )
{
    if( c ) m_autoClose |= 1<<3; 
    else    m_autoClose &= ~(1<<3); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setAutoClose( m_autoClose ); 
}

void EditorWidget::setCloseSquotes( bool c )
{
    if( c ) m_autoClose |= 1<<4; 
    else    m_autoClose &= ~(1<<4); 

    for( CodeEditor* ce : getCodeEditors() ) ce->setAutoClose( m_autoClose ); 
}

CodeEditor* EditorWidget::getCodeEditor()
{
    return (CodeEditor*)m_docWidget->currentWidget(); 
}

QList<CodeEditor*> EditorWidget::getCodeEditors()
{
    QList<CodeEditor*> list; 
    for( QWidget* widget : m_fileList.values() ) list.append( (CodeEditor*)widget ); 
    return list; 
}

bool EditorWidget::close()
{
    int count = m_docWidget->count(); 
    for( int i=0;  i<count;  i++ )
    {
        m_docWidget->setCurrentIndex( i ); 
        if( !maybeSave() ) return false; 
    }
    while( m_docWidget->count() )
    {
        m_docWidget->setCurrentIndex( 0 ); 
        closeTab( 0 ); 
    }
    writeSettings(); 
    return true; 
}

void EditorWidget::newFile()
{
    addDocument( "", true ); 
}

void EditorWidget::addDocument(  QString file, bool main  )
{
    CodeEditor* ce = new CodeEditor( this, &m_outPane ); 
    ce->setVerticalScrollBar( new scrollWidget( ce, Qt::Vertical ) ); 
    ce->setTabStopDistance( calcTabstopWidth() ); 
    ce->setAutoClose( m_autoClose ); 
    docShowSpaces( ce ); 

    QString tabString = file.isEmpty() ? tr("NEW") : getFileName(file); 
    m_docWidget->addTab( ce, tabString ); 

    if( !file.isEmpty() ){
        ce->setPlainText( fileToString( file, "EditorWidget::addDocument" ) ); 
        ce->setFile( file ); 
    }
    connect( ce->document(), &QTextDocument::contentsChanged,
                       this, &EditorWidget::documentWasModified, Qt::UniqueConnection); 

    m_fileList[file] = ce; 
    if( main ){
        m_docWidget->setCurrentWidget( ce ); 
        if( file.isEmpty() ) ce->document()->setModified( true );  // New
        documentWasModified(); 
        enableFileActs( true ); 
        enableDebugActs( true ); 
        updateDoc(); 
    }
}

int EditorWidget::calcTabstopWidth() 
{
    QFontMetrics fm( m_font ); 
    QString spaces( m_tabSize, QChar(' ') ); 
    return fm.horizontalAdvance( spaces ); 
}

void EditorWidget::open()
{
    QString dir = m_lastDir; 
    QString fileName = QFileDialog::getOpenFileName( this, tr("Load File"), dir,
                       tr("All files")+" (*); ; Arduino (*.ino); ; Asm (*.asm); ; GcBasic (*.gcb)" ); 

    if( !fileName.isEmpty() ) loadFile( fileName ); 
}

void EditorWidget::openRecentFile()
{
    QAction* action = qobject_cast<QAction*>( sender() ); 
    if( action )
    {
        QString file = action->data().toString(); 
        QFile pfile( file ); 
        if( pfile.exists() ) loadFile( file ); 
        else{
            QMessageBox::StandardButton ret
            = QMessageBox::warning( this, "EditorWidget::openRecentFile",
                                   tr("\nCan't find file:\n")+
                                   file+"\n\n"+
                                   tr("Do you want to remove it from Recent Files?\n"),
              QMessageBox::Yes | QMessageBox::No ); 

            if( ret == QMessageBox::Yes )
            {
                QSettings* settings = MainWindow::self()->settings(); 
                QStringList files = settings->value("recentFileList").toStringList(); 
                files.removeAll( file ); 
                settings->setValue("recentFileList", files ); 
                updateRecentFileActions(); 
            }
        }
    }
}

void EditorWidget::dragEnterEvent( QDragEnterEvent* event)
{
    event->accept(); 
}

void EditorWidget::dropEvent( QDropEvent* event )
{
    QString id = event->mimeData()->text(); 

    QString file = "file://"; 
    if( id.startsWith( file ) )
    {
        id.replace( file, "" ).replace("\r\n", "" ).replace("%20", " "); 
#ifdef _WIN32
        if( id.startsWith( "/" )) id.remove( 0, 1 ); 
#endif
        loadFile( id ); 
    }
}

void EditorWidget::keyPressEvent( QKeyEvent* event )
{
    if( event->modifiers() & Qt::ControlModifier )
    {
        if     ( event->key() == Qt::Key_N ) newFile(); 
        else if( event->key() == Qt::Key_O ) open(); 
        else if( event->key() == Qt::Key_R ) reload(); 
        else if( event->key() == Qt::Key_S )
        {
            if( event->modifiers() & Qt::ShiftModifier) saveAs(); 
            else                                        save(); 
        }
    }
}

void EditorWidget::restoreFile( QString filePath )
{
    if( !QFileInfo::exists( filePath ) )
    {
        m_outPane.appendLine( tr("File doesn't exist")+":\n"+filePath ); 
        return; 
    }
    if( m_fileList.contains( filePath ) ) return; 

    addDocument( filePath, false ); 
}

void EditorWidget::loadFile( QString filePath )
{
    if( !QFileInfo::exists( filePath ) )
    {
        m_outPane.appendLine( tr("File doesn't exist")+":\n"+filePath ); 
        return; 
    }
    if( m_fileList.contains( filePath ) )
    {
        m_docWidget->setCurrentWidget( m_fileList.value( filePath ) ); 
        return; 
    }
    QApplication::setOverrideCursor( Qt::WaitCursor ); 

    m_lastDir = filePath; 
    addDocument( filePath, true ); 
    enableFileActs( true ); 
    enableDebugActs( true ); 
    addRecentFile( filePath ); 

    QApplication::restoreOverrideCursor(); 
}

void EditorWidget::reload()
{
    CodeEditor* ce = getCodeEditor(); 
    QString file = m_fileList.key( m_docWidget->currentWidget() ); 
    ce->setPlainText( fileToString( file, "EditorWidget::reload" ) ); 
    ce->document()->setModified( false ); 
    documentWasModified(); 
}

bool EditorWidget::save()
{
    QString file = getCodeEditor()->getFile(); 
    if( file.isEmpty() ) return saveAs(); 
    else                 return saveFile( file ); 
}

bool EditorWidget::saveAs()
{
    CodeEditor* ce = getCodeEditor(); 

    QFileInfo fi = QFileInfo( ce->getFile() ); 
    QString ext  = fi.suffix(); 
    QString path = fi.absolutePath(); 
    if( path == "" ) path = m_lastDir; 

    QString extensions = ""; 
    if( ext == "" ) extensions = tr("All files")+" (*); ; Arduino (*.ino); ; Asm (*.asm); ; GcBasic (*.gcb)"; 
    else            extensions = "."+ext+"(*."+ext+"); ; "+tr("All files")+" (*.*)"; 

    QString fileName = QFileDialog::getSaveFileName( MainWindow::self(), tr("Save Document As"), path, extensions ); 
    if( fileName.isEmpty() ) return false; 

    m_fileList.remove( ce->getFile() ); 
    m_fileList[fileName] = ce; 

    return saveFile( fileName ); 
}

bool EditorWidget::saveFile( QString fileName )
{
    QFile file( fileName ); 
    if( !file.open( QFile::WriteOnly | QFile::Text) )
    {
        QMessageBox::warning(this, "EditorWindow::saveFile",
                             tr("Cannot write file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString())); 
        return false; 
    }
    QApplication::setOverrideCursor( Qt::WaitCursor ); 

    QTextStream out( &file ); 
    out.setCodec("UTF-8"); 

    CodeEditor* ce = getCodeEditor(); 
    out << ce->toPlainText(); 
    file.close(); 

    //ce->saveConfig(); 
    ce->document()->setModified( false ); 
    documentWasModified(); 

    m_docWidget->setTabText( m_docWidget->currentIndex(), getFileName(fileName) ); 
    ce->setFile( fileName ); 

    QApplication::restoreOverrideCursor(); 
    return true; 
}

bool EditorWidget::maybeSave()
{
    if( m_fileList.isEmpty() ) return true; 
    if( getCodeEditor()->document()->isModified() )
    {
        QMessageBox::StandardButton ret; 
        ret = QMessageBox::warning( this, "EditorWindow::saveFile",
              tr("\nThe Document has been modified.\nDo you want to save your changes?\n"),
              QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); 

        if     ( ret == QMessageBox::Save )   return save(); 
        else if( ret == QMessageBox::Cancel ) return false; 
    }
    return true; 
}

void EditorWidget::documentWasModified()
{
    CodeEditor* ce = getCodeEditor(); 
    QTextDocument *doc = ce->document(); 

    bool    modified = doc->isModified(); 
    int     index    = m_docWidget->currentIndex(); 
    QString tabText  = m_docWidget->tabText( index ); 

    if     ( modified && !tabText.endsWith("*") ) tabText.append("*"); 
    else if( !modified && tabText.endsWith("*") ) tabText.remove("*"); 

    m_docWidget->setTabText( index, tabText ); 

    redoAct->setEnabled( false ); 
    undoAct->setEnabled( false ); 
    if( doc->isRedoAvailable() ) redoAct->setEnabled( true ); 
    if( doc->isUndoAvailable() ) undoAct->setEnabled( true ); 
}

void EditorWidget::updateDoc( int )
{
    CodeEditor* ce = getCodeEditor(); 
    m_findRepDialog->setEditor( ce ); 
    if( !ce ) return; 
    bool show = ce->compName() == "None" ? false : true; 
    confCompAct->setVisible( show ); 
    confFileAct->setVisible( true ); 
}

void EditorWidget::closeTab( int index )
{
    if( m_debuggerToolBar->isVisible() ) stop(); 

    m_docWidget->setCurrentIndex( index ); 
    if( !maybeSave() ) return; 

    CodeEditor* ce = getCodeEditor(); 
    ce->closing(); 
    m_fileList.remove( m_fileList.key( ce ) ); 
    m_docWidget->removeTab( index ); 
    delete ce; 

    if( m_fileList.isEmpty() )  // disable file actions
    {
        enableFileActs( false ); 
        enableDebugActs( false ); 
        m_findRepDialog->hide(); 
        confFileAct->setVisible( false ); 
        confCompAct->setVisible( false ); 
    }

    int last = m_docWidget->count()-1; 
    if( index > last ) index = last; 
    m_docWidget->setCurrentIndex( index ); 

    m_findRepDialog->setEditor( getCodeEditor() ); 
}

void EditorWidget::confEditor()
{
    if( !m_propDialog )
    {
        if( m_help == "" ) m_help = MainWindow::self()->getHelp( "editor" ); 

        m_propDialog = new PropDialog( this, m_help ); 
        m_propDialog->setComponent( this, false ); 
    }
    m_propDialog->show(); 
}

void EditorWidget::confFile()
{
    CodeEditor* ce = getCodeEditor(); 
    if( ce ) ce->fileProps(); 
}

void EditorWidget::confCompiler()
{
    CodeEditor* ce = getCodeEditor(); 
    if( !ce ) return; 
    Compiler* c = ce->getCompiler(); 
    if( !c || c->compName() == "None" ) return; 
    c->compilerProps(); 
}

void EditorWidget::addRecentFile( QString filePath )
{
    QSettings* settings = MainWindow::self()->settings(); 
    QStringList files = settings->value("recentFileList").toStringList(); 
    files.removeAll( filePath ); 
    files.prepend( filePath ); 
    while( files.size() > MaxRecentFiles ) files.removeLast(); 
    settings->setValue("recentFileList", files ); 
    updateRecentFileActions(); 
}

void EditorWidget::updateRecentFileActions()
{
    QSettings* settings = MainWindow::self()->settings(); 
    QStringList files = settings->value("recentFileList").toStringList(); 

    int numRecentFiles = qMin( files.size(), (int)MaxRecentFiles ); 

    for( int i=0;  i<numRecentFiles;  i++ )
    {
        QString text = QString::number(i + 1)+" "+getFileName( files[i] ); 
        recentFileActs[i]->setText(text); 
        recentFileActs[i]->setData( files[i] ); 
        recentFileActs[i]->setVisible( true ); 
    }
    for( int i=numRecentFiles;  i<MaxRecentFiles;  i++ ) recentFileActs[i]->setVisible(false); 
}

void EditorWidget::readSettings()
{
    QSettings* settings = MainWindow::self()->settings(); 

    m_showSpaces = false; 
    m_spaceTabs  = false; 
    m_autoClose = 0; 
    m_fontSize = 14; 
    m_tabSize = 4; 

    m_font.setFamily("Ubuntu Mono"); 
    m_font.setWeight( QFont::Normal ); 
    m_font.setPixelSize( m_fontSize ); 

    if( settings->contains( "Editor_show_spaces" ) )
        setShowSpaces( settings->value( "Editor_show_spaces" ).toBool() ); 

    if( settings->contains( "Editor_tab_size" ) )
        setTabSize( settings->value( "Editor_tab_size" ).toInt() ); 
    else setTabSize( 4 ); 

    if( settings->contains( "Editor_font_size" ) )
        setFontSize( settings->value( "Editor_font_size" ).toInt() ); 

    bool spacesTab = false; 
    if( settings->contains( "Editor_spaces_tabs" ) )
        spacesTab = settings->value( "Editor_spaces_tabs" ).toBool(); 

    if( settings->contains( "Editor_autoclose" ) )
        setAutoClose( settings->value( "Editor_autoclose" ).toInt() ); 

    setSpaceTabs( spacesTab ); 

    restoreGeometry( settings->value("geometry").toByteArray() ); 
    m_docWidget->restoreGeometry( settings->value("docWidget/geometry").toByteArray() ); 
    m_lastDir = settings->value("lastDir").toString(); 
}

void EditorWidget::writeSettings()
{
    QSettings* settings = MainWindow::self()->settings(); 
    settings->setValue( "geometry", saveGeometry() ); 
    settings->setValue( "docWidget/geometry", m_docWidget->saveGeometry() ); 
    settings->setValue( "lastDir", m_lastDir ); 
    settings->setValue( "Editor_autoclose", QString::number( m_autoClose ) ); 
}

void EditorWidget::findReplaceDialog()
{
    CodeEditor* ce = getCodeEditor(); 

    m_findRepDialog->setEditor( ce ); 

    QString text =ce->textCursor().selectedText(); 
    if( text != "" ) m_findRepDialog->setTextToFind( text ); 

    m_findRepDialog->show(); 
}

void EditorWidget::enableFileActs( bool enable )
{
    saveAct->setEnabled( enable ); 
    saveAsAct->setEnabled( enable ); 
    cutAct->setEnabled( enable ); 
    copyAct->setEnabled( enable ); 
    pasteAct->setEnabled( enable ); 
    undoAct->setEnabled( enable ); 
    redoAct->setEnabled( enable ); 
    findQtAct->setEnabled( enable ); 
}

void EditorWidget::enableDebugActs( bool enable )
{
    debugAct->setEnabled( enable ); 
    runAct->setEnabled( enable ); 
    stepAct->setEnabled( enable ); 
    stepOverAct->setEnabled( enable ); 
    pauseAct->setEnabled( enable ); 
    resetAct->setEnabled( enable ); 
    stopAct->setEnabled( enable ); 
    compileAct->setEnabled( enable ); 
    loadAct->setEnabled( enable ); 
}

void EditorWidget::setStepActs( bool s )
{
    runAct->setEnabled( s ); 
    stepAct->setEnabled( s ); 
    stepOverAct->setEnabled( s ); 
    resetAct->setEnabled( s ); 
    pauseAct->setEnabled( !s ); 
}

void EditorWidget::createWidgets()
{
    QHBoxLayout* hLayout = new QHBoxLayout(); 
    hLayout->setSpacing(0); 
    hLayout->setContentsMargins(0, 0, 0, 0); 

    QVBoxLayout* vLayout = new QVBoxLayout( this ); 
    vLayout->setSpacing(0); 
    vLayout->setContentsMargins(0, 0, 0, 0); 

    hLayout->addWidget( m_editorToolBar ); 
    hLayout->addWidget( m_findToolBar ); 
    hLayout->addWidget( m_compileToolBar ); 
    hLayout->addWidget( m_debuggerToolBar ); 
    hLayout->addStretch(); 
    vLayout->addLayout( hLayout ); 

    QSplitter* splitter0 = new QSplitter( this ); 
    splitter0->setObjectName("splitter0"); 
    splitter0->setOrientation( Qt::Vertical ); 
    vLayout->addWidget( splitter0 ); 

    m_docWidget = new QTabWidget( this ); 
    m_docWidget->setObjectName("docWidget"); 
    m_docWidget->setTabPosition( QTabWidget::North ); 
    m_docWidget->setTabsClosable ( true ); 
    m_docWidget->setContextMenuPolicy( Qt::CustomContextMenu ); 

    //double fontScale = MainWindow::self()->fontScale(); 
    //QString fontSize = QString::number( int(10*fontScale) ); 
    //m_docWidget->tabBar()->setStyleSheet("QTabBar { font-size:"+fontSize+"px;  }"); 
    m_docWidget->setMovable( true ); 

    splitter0->addWidget( m_docWidget ); 
    splitter0->addWidget( &m_outPane ); 
    splitter0->setSizes( {300, 100} ); 

    connect( m_docWidget, SIGNAL( tabCloseRequested(int)),
             this,        SLOT(   closeTab(int)), Qt::UniqueConnection); 

    connect( m_docWidget, SIGNAL(currentChanged(int)), this, SLOT(updateDoc(int)), Qt::UniqueConnection); 

    m_findRepDialog = new FindReplace( this ); 
    m_findRepDialog->setModal( false ); 
}

void EditorWidget::createActions()
{
    confEditAct = new QAction(QIcon(":/blank.png"), tr("Editor Settings"), this); 
    confEditAct->setStatusTip(tr("Editor Settings")); 
    connect( confEditAct, SIGNAL(triggered()), this, SLOT(confEditor()), Qt::UniqueConnection); 

    confFileAct = new QAction(QIcon(":/blank.png"), tr("File Settings"), this); 
    confFileAct->setStatusTip(tr("Compiler Settings")); 
    connect( confFileAct, SIGNAL(triggered()), this, SLOT(confFile()), Qt::UniqueConnection); 
    confFileAct->setVisible( false ); 

    confCompAct = new QAction(QIcon(":/blank.png"), tr("Compiler Settings"), this); 
    confCompAct->setStatusTip(tr("Compiler Settings")); 
    connect( confCompAct, SIGNAL(triggered()), this, SLOT(confCompiler()), Qt::UniqueConnection); 
    confCompAct->setVisible( false ); 

    for( int i=0;  i<MaxRecentFiles;  i++ )
    {
        recentFileActs[i] = new QAction( this ); 
        recentFileActs[i]->setVisible( false ); 
        connect( recentFileActs[i], SIGNAL( triggered() ),
                 this,              SLOT( openRecentFile() ), Qt::UniqueConnection); 
    }

    newAct = new QAction(QIcon(":/new.svg"), tr("&New\tCtrl+N"), this); 
    newAct->setStatusTip(tr("Create a new file")); 
    connect( newAct, SIGNAL(triggered()), this, SLOT(newFile()), Qt::UniqueConnection); 

    openAct = new QAction(QIcon(":/open.svg"), tr("&Open...\tCtrl+O"), this); 
    openAct->setStatusTip(tr("Open an existing file")); 
    connect(openAct, SIGNAL(triggered()), this, SLOT(open()), Qt::UniqueConnection); 

    saveAct = new QAction(QIcon(":/save.svg"), tr("&Save\tCtrl+S"), this); 
    saveAct->setStatusTip(tr("Save the document to disk")); 
    saveAct->setEnabled(false); 
    connect(saveAct, SIGNAL(triggered()), this, SLOT(save()), Qt::UniqueConnection); 

    saveAsAct = new QAction(QIcon(":/saveas.svg"),tr("Save &As...\tCtrl+Shift+S"), this); 
    saveAsAct->setStatusTip(tr("Save the document under a new name")); 
    saveAsAct->setEnabled(false); 
    connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()), Qt::UniqueConnection); 

    cutAct = new QAction(QIcon(":/cut.svg"), tr("Cu&t\tCtrl+X"), this); 
    cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard")); 
    cutAct->setEnabled(false); 
    connect(cutAct, SIGNAL(triggered()), this, SLOT(cut()), Qt::UniqueConnection); 

    copyAct = new QAction(QIcon(":/copy.svg"), tr("&Copy\tCtrl+C"), this); 
    copyAct->setStatusTip(tr("Copy the current selection's contents to the clipboard")); 
    copyAct->setEnabled(false); 
    connect(copyAct, SIGNAL(triggered()), this, SLOT(copy()), Qt::UniqueConnection); 

    pasteAct = new QAction(QIcon(":/paste.svg"), tr("&Paste\tCtrl+V"), this); 
    pasteAct->setStatusTip(tr("Paste the clipboard's contents into the current selection")); 
    pasteAct->setEnabled(false); 
    connect(pasteAct, SIGNAL(triggered()), this, SLOT(paste()), Qt::UniqueConnection); 

    undoAct = new QAction(QIcon(":/undo.svg"), tr("Undo\tCtrl+Z"), this); 
    undoAct->setStatusTip(tr("Undo the last action")); 
    undoAct->setEnabled(false); 
    connect(undoAct, SIGNAL(triggered()), this, SLOT(undo()), Qt::UniqueConnection); 

    redoAct = new QAction(QIcon(":/redo.svg"), tr("Redo\tCtrl+Shift+Z"), this); 
    redoAct->setStatusTip(tr("Redo the last action")); 
    redoAct->setEnabled(false); 
    connect(redoAct, SIGNAL(triggered()), this, SLOT(redo())); 

    runAct =  new QAction(QIcon(":/runtobk.png"),tr("Run To Breakpoint"), this); 
    runAct->setStatusTip(tr("Run to next breakpoint")); 
    runAct->setEnabled(false); 
    connect(runAct, SIGNAL(triggered()), this, SLOT(run()), Qt::UniqueConnection); 

    stepAct = new QAction(QIcon(":/step.svg"),tr("Step"), this); 
    stepAct->setStatusTip(tr("Step debugger")); 
    stepAct->setEnabled(false); 
    connect( stepAct, SIGNAL(triggered()), this, SLOT(step()), Qt::UniqueConnection ); 

    stepOverAct = new QAction(QIcon(":/rotatecw.svg"),tr("StepOver"), this); 
    stepOverAct->setStatusTip(tr("Step Over")); 
    stepOverAct->setEnabled(false); 
    stepOverAct->setVisible(false); 
    connect( stepOverAct, SIGNAL(triggered()), this, SLOT(stepOver()), Qt::UniqueConnection ); 

    pauseAct = new QAction(QIcon(":/pause.svg"),tr("Pause"), this); 
    pauseAct->setStatusTip(tr("Pause debugger")); 
    pauseAct->setEnabled(false); 
    connect( pauseAct, SIGNAL(triggered()), this, SLOT(pause()), Qt::UniqueConnection ); 

    resetAct = new QAction(QIcon(":/reset.svg"),tr("Reset"), this); 
    resetAct->setStatusTip(tr("Reset debugger")); 
    resetAct->setEnabled(false); 
    connect( resetAct, SIGNAL(triggered()), this, SLOT(reset()), Qt::UniqueConnection ); 

    stopAct = new QAction(QIcon(":/stop.svg"),tr("Stop Debugger"), this); 
    stopAct->setStatusTip(tr("Stop debugger")); 
    stopAct->setEnabled(false); 
    connect( stopAct, SIGNAL(triggered()), this, SLOT(stop()), Qt::UniqueConnection ); 

    compileAct = new QAction(QIcon(":/verify.svg"),tr("Compile"), this); 
    compileAct->setStatusTip(tr("Compile Source")); 
    compileAct->setEnabled(false); 
    connect( compileAct, SIGNAL(triggered()), this, SLOT(compile()), Qt::UniqueConnection ); 

    loadAct = new QAction(QIcon(":/upload.svg"),tr("UpLoad"), this); 
    loadAct->setStatusTip(tr("Load Firmware")); 
    loadAct->setEnabled(false); 
    connect( loadAct, SIGNAL(triggered()), this, SLOT(upload()), Qt::UniqueConnection ); 

    findQtAct = new QAction(QIcon(":/find.svg"),tr("Find Replace"), this); 
    findQtAct->setStatusTip(tr("Find Replace")); 
    findQtAct->setEnabled(false); 
    connect(findQtAct, SIGNAL(triggered()), this, SLOT(findReplaceDialog()), Qt::UniqueConnection); 

    debugAct =  new QAction(QIcon(":/debug.svg"),tr("Debug"), this); 
    debugAct->setStatusTip(tr("Start Debugger")); 
    debugAct->setEnabled(false); 
    connect(debugAct, SIGNAL(triggered()), this, SLOT(debug()), Qt::UniqueConnection); 
}

void EditorWidget::createToolBars()
{
    m_settingsMenu.addAction( confEditAct ); 
    m_settingsMenu.addAction( confFileAct ); 
    m_settingsMenu.addAction( confCompAct ); 

    m_settingsButton = new QToolButton( this ); 
    m_settingsButton->setToolTip( tr("Settings") ); 
    m_settingsButton->setMenu( &m_settingsMenu ); 
    m_settingsButton->setIcon( QIcon(":/config.svg") ); 
    m_settingsButton->setPopupMode( QToolButton::InstantPopup ); 

    for( int i=0;  i<MaxRecentFiles;  i++ ) m_fileMenu.addAction( recentFileActs[i] ); 
    m_fileButton = new QToolButton( this ); 
    m_fileButton->setToolTip( tr("Last Files") ); 
    m_fileButton->setMenu( &m_fileMenu ); 
    m_fileButton->setIcon( QIcon(":/lastfiles.svg") ); 
    m_fileButton->setPopupMode( QToolButton::InstantPopup ); 

    double fs = MainWindow::self()->fontScale()*20; 

    m_editorToolBar = new QToolBar( this ); 
    m_editorToolBar->setIconSize( QSize( fs, fs ) ); 
    m_editorToolBar->addWidget( m_settingsButton ); 
    QWidget* spacer = new QWidget(); 
    spacer->setFixedWidth( 15 ); 
    m_editorToolBar->addWidget( spacer ); 
    m_editorToolBar->addSeparator(); //..........................
    m_editorToolBar->addWidget( m_fileButton ); 

    m_editorToolBar->addAction(newAct); 
    m_editorToolBar->addAction(openAct); 
    m_editorToolBar->addAction(saveAct); 
    m_editorToolBar->addAction(saveAsAct); 
    m_editorToolBar->addSeparator(); 

    m_findToolBar = new QToolBar( this ); 
    m_findToolBar->setIconSize( QSize( fs, fs ) ); 
    m_findToolBar->addAction(findQtAct); 
    m_findToolBar->addSeparator(); 

    m_compileToolBar = new QToolBar( this ); 
    m_compileToolBar->setIconSize( QSize( fs, fs ) ); 
    m_compileToolBar->addAction(compileAct); 
    m_compileToolBar->addAction(loadAct); 
    m_compileToolBar->addSeparator(); 
    m_compileToolBar->addAction(debugAct); 

    m_debuggerToolBar = new QToolBar( this ); 
    m_debuggerToolBar->setIconSize( QSize( fs, fs ) ); 
    m_debuggerToolBar->addAction(stepAct); 
    m_debuggerToolBar->addAction(stepOverAct); 
    m_debuggerToolBar->addAction(runAct); 
    m_debuggerToolBar->addAction(pauseAct); 
    m_debuggerToolBar->addAction(resetAct); 
    m_debuggerToolBar->addSeparator(); 
    m_debuggerToolBar->addAction(stopAct); 
    m_debuggerToolBar->setVisible( false ); 
}

void EditorWidget::updateIcons()
{
    newAct->setIcon(      ThemeManager::self()->icon(":/new.svg") ); 
    openAct->setIcon(     ThemeManager::self()->icon(":/open.svg") ); 
    saveAct->setIcon(     ThemeManager::self()->icon(":/save.svg") ); 
    saveAsAct->setIcon(   ThemeManager::self()->icon(":/saveas.svg") ); 

    cutAct->setIcon(      ThemeManager::self()->icon(":/cut.svg") ); 
    copyAct->setIcon(     ThemeManager::self()->icon(":/copy.svg") ); 
    pasteAct->setIcon(    ThemeManager::self()->icon(":/paste.svg") ); 

    undoAct->setIcon(     ThemeManager::self()->icon(":/undo.svg") ); 
    redoAct->setIcon(     ThemeManager::self()->icon(":/redo.svg") ); 

    runAct->setIcon(      ThemeManager::self()->icon(":/runtobk.png") ); 
    stepAct->setIcon(     ThemeManager::self()->icon(":/step.svg") ); 
    stepOverAct->setIcon( ThemeManager::self()->icon(":/rotatecw.svg") ); 
    pauseAct->setIcon(    ThemeManager::self()->icon(":/pause.svg") ); 
    resetAct->setIcon(    ThemeManager::self()->icon(":/reset.svg") ); 
    stopAct->setIcon(     ThemeManager::self()->icon(":/stop.svg") ); 

    compileAct->setIcon(  ThemeManager::self()->icon(":/verify.svg") ); 
    loadAct->setIcon(     ThemeManager::self()->icon(":/upload.svg") ); 
    findQtAct->setIcon(   ThemeManager::self()->icon(":/find.svg") ); 
    debugAct->setIcon(    ThemeManager::self()->icon(":/debug.svg") ); 

    m_settingsButton->setIcon( ThemeManager::self()->icon(":/config.svg") ); 
    m_fileButton->setIcon(     ThemeManager::self()->icon(":/lastfiles.svg") ); 

    for( CodeEditor* ce : getCodeEditors() ) ce->reloadSyntax(); 
}

#include  "moc_editorwidget.cpp"
