# HG changeset patch # User Jacob Dawid # Date 1302776645 -7200 # Node ID e7e671d727b2f18aa55ba8a64c5091d7d270d226 # Parent 8b09300bbf2935f9396fed54e456bd2984e6ee44 Updated and patched text editor from QtOctave. diff -r 8b09300bbf29 -r e7e671d727b2 gui//Quint.pro --- a/gui//Quint.pro Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//Quint.pro Thu Apr 14 12:24:05 2011 +0200 @@ -43,11 +43,11 @@ src/VariablesDockWidget.cpp \ src/HistoryDockWidget.cpp \ src/FilesDockWidget.cpp \ - src/CodeEdit.cpp \ src/FileEditorMdiSubWindow.cpp \ src/SyntaxHighlighter.cpp \ src/BrowserWidget.cpp \ - src/NumberedCodeEdit.cpp + src/NumberedCodeEdit.cpp \ + src/SimpleEditor.cpp HEADERS += \ src/TerminalCharacterDecoder.h \ @@ -87,11 +87,11 @@ src/VariablesDockWidget.h \ src/HistoryDockWidget.h \ src/FilesDockWidget.h \ - src/CodeEdit.h \ src/FileEditorMdiSubWindow.h \ src/SyntaxHighlighter.h \ src/BrowserWidget.h \ - src/NumberedCodeEdit.h + src/NumberedCodeEdit.h \ + src/SimpleEditor.h INCFLAGS = -g3 $$system(mkoctfile -p INCFLAGS) LFLAGS = $$system(mkoctfile -p LFLAGS) \ diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/CodeEdit.cpp --- a/gui//src/CodeEdit.cpp Thu Apr 14 10:27:09 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,316 +0,0 @@ -/* Copyright (C) 2007 Alejandro Álvarez - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "CodeEdit.h" - -CodeEdit::CodeEdit(QWidget *parent) - : QPlainTextEdit(parent), - contextMenu(this) { - - m_syntaxHighlighter=new SyntaxHighlighter(document()); - - setUndoRedoEnabled(true); - setTabStopWidth(32); - setFrameStyle(QFrame::NoFrame); - - autocompletion_ok=true;//(get_config("autoCompletion")!="false"); - - // ContextMenu - - connect(contextMenu.addAction(tr("Undo")), SIGNAL(triggered()), - this, SLOT(undo())); - connect(contextMenu.addAction(tr("Redo")), SIGNAL(triggered()), - this, SLOT(redo())); - - contextMenu.addSeparator(); - - connect(contextMenu.addAction(tr("Cut")), SIGNAL(triggered()), - this, SLOT(cut())); - connect(contextMenu.addAction(tr("Copy")), SIGNAL(triggered()), - this, SLOT(copy())); - connect(contextMenu.addAction(tr("Paste")), SIGNAL(triggered()), - this, SLOT(paste())); - connect(contextMenu.addAction(tr("Delete")), SIGNAL(triggered()), - this, SLOT(deleteSelection())); - - contextMenu.addSeparator(); - - connect(contextMenu.addAction(tr("Select all")), SIGNAL(triggered()), - this, SLOT(selectAll())); - - contextMenu.addSeparator(); - - connect(contextMenu.addAction(tr("Toggle breakpoint")), SIGNAL(triggered()), - this, SLOT(toggleBreakpoint())); - - //connect(this->document(), SIGNAL( contentsChange ( int , int , int )), this, SLOT(buildUndoRedoStack(int , int , int)) ); - - if(autocompletion_ok) - { - connect(this->document(), SIGNAL( contentsChange ( int , int , int )), this, SLOT(buildAutoCompletionList(int , int , int)) ); - connect(&completion, SIGNAL(activated ( const QModelIndex &)), this, SLOT(doCompletion(const QModelIndex &)) ); - } - - - octaveCommandTimer.setSingleShot(true); - octaveCommandTimer.setInterval(2000); - - connect(&octaveCommandTimer, SIGNAL(timeout ()), this, SLOT(octaveCommandCompletion())); - - completionTimer.setSingleShot(true); - completionTimer.setInterval(200); - - connect(&completionTimer, SIGNAL(timeout ()), this, SLOT(buildAutoCompletionList())); - - auto_indent=true; - setAcceptDrops(false); - if(autocompletion_ok) - { - completion.setWidget(this); - completion_model=new QStringListModel(&completion); - completion.setModel(completion_model); - completion.setCompletionMode(QCompleter::UnfilteredPopupCompletion); - } - - text_modified_stop_ok=context_changed_ok=false; - - connect(document(), SIGNAL(modificationChanged (bool)), this, SLOT(textModified_cb(bool))); - - auto_indent=true;//("false"!=get_config("autoindent")); - automatic_indention_statement_ok=true;//(get_config("autoindent_statements")=="true"); -} - -CodeEdit::~CodeEdit() { - delete m_syntaxHighlighter; -} - -void CodeEdit::contextMenuEvent(QContextMenuEvent *contextMenuEvent) { - contextMenu.exec(contextMenuEvent->globalPos()); -} - -void CodeEdit::undo() { - document()->undo(); -} - -void CodeEdit::redo() { - document()->redo(); -} - -void CodeEdit::deleteSelection() { - textCursor().removeSelectedText(); -} - -void CodeEdit::toggleBreakpoint() { - int line = 1; - for(QTextBlock tb = document()->begin(); tb.isValid(); line++, tb = tb.next()) { - if(tb == textCursor().block()) { - emit toggleBreakpoint(line); - return; - } - } -} - -bool CodeEdit::event(QEvent * event) { - if(QEvent::KeyPress==event->type()) - { - QKeyEvent *k=(QKeyEvent *)event; - if(autocompletion_ok && (Qt::Key_Left==k->key() || Qt::Key_Right==k->key())) { - completion.popup()->hide(); - } else if(Qt::Key_Return==k->key() || Qt::Key_Enter==k->key()) { - if(autocompletion_ok && !completion.popup()->isHidden()) { - doCompletion(completion.popup()->currentIndex()); - } else if(auto_indent) { - QTextCursor cursor=textCursor(); - int pos=cursor.position(); - cursor.movePosition(QTextCursor::StartOfBlock,QTextCursor::KeepAnchor); - QString line=cursor.selectedText(); - QString start_blank; - start_blank.append('\n'); - for(int i=0;isetModified(true); - context_changed_ok=true; - - completionPosition=pos; - completionTimer.start(); - completion.popup()->hide(); -} - -void CodeEdit::buildAutoCompletionList() { - QTextCursor cursor=textCursor(); - int pos=cursor.position()-1; - //printf("[CodeEdit::buildAutoCompletionList] pos=%d completionPosition=%d\n", pos, completionPosition); - if(pos!=completionPosition) - return; - - QTextBlock block=document()->findBlock(pos); - - pos-=block.position(); - int i=pos; - QString text=block.text(); - QRegExp re("([^a-zA-Z_0-9]+)"); - i=re.lastIndexIn(text, i); - //printf("pos=%d i=%d len=%d\n", pos, i, re.matchedLength()); - if( i==pos ) {completion.popup()->hide();return;} - QString word_to_complete=text.mid(i+1,pos-i); - //printf("i=%d word=>%s<\n",i, word_to_complete.toLocal8Bit().data()); - QString actual_word; - re.setPattern("([a-zA-Z_0-9]+)"); - i=re.indexIn(text, pos); - if( i==pos ) actual_word=word_to_complete+text.mid(pos+1,re.matchedLength()-1); - //printf("i=%d word=>%s<\n",i, actual_word.toLocal8Bit().data()); - - if(word_to_complete.length()==2) { - completion_model->setStringList(m_syntaxHighlighter->octave_comands); - completion.setCompletionPrefix(word_to_complete); - completion.popup()->hide(); - - octaveCommandTimer.start(); - return; - } - else if(word_to_complete.length()<3) {completion.popup()->hide();return;} - - emit dynamicHelpRequired(word_to_complete); - - //Se construye la lista de palabras a completar - - QTextBlock blockInit, blockEnd; - blockInit=document()->firstBlock(); - blockEnd =document()->lastBlock(); - completion_list.clear(); - buildAutoCompletionListSlide(completion_list, blockInit, blockEnd, word_to_complete, actual_word); - - if(completion_list.isEmpty()) {completion.popup()->hide();return;} - - completion_model->setStringList(completion_list); - - - QRect _position=cursorRect(); - - //printf("x=%d y=%d width=%d height=%d\n", _position.x(), _position.y(), _position.width(), _position.height() ); - - //_position.moveTo(_position.bottomRight() ); - ////_position.setWidth(100); - _position.setWidth(width()/3); - - completion.setCompletionPrefix(word_to_complete); - completion.complete(_position); - completion.popup()->show(); - completion.popup()->setFocus(Qt::TabFocusReason); -} - -void CodeEdit::buildAutoCompletionListSlide(QStringList &list, QTextBlock blockInit, QTextBlock blockEnd, QString word_to_complete, QString actual_word) { - //QStringList list; - - //printf("Buscando lista\n"); - //block=document()->findBlock(0); - - QTextBlock block=blockInit; - - //QString match; - QRegExp rx("([a-zA-Z_0-9]+)"); - - while( block.isValid() ) - { - QString text=block.text(); - int i = 0; - - while ((i = rx.indexIn(text, i)) != -1) { - QString word=rx.cap(1); - if( word.startsWith(word_to_complete) && !list.contains(word) && word!=actual_word ) - { - list << word; - //printf("i=%d word=>%s< actual_word=>%s<\n",i, word.toLocal8Bit().data(), actual_word.toLocal8Bit().data()); - } - i += rx.matchedLength(); - } - - if(block!=blockEnd) block=block.next(); - else break; - } -} - -void CodeEdit::octaveCommandCompletion() { - QRect _position=cursorRect(); - - _position.setWidth(width()); - - completion.complete(_position); - completion.popup()->show(); - completion.popup()->setFocus(Qt::TabFocusReason); -} - - -void CodeEdit::doCompletion(const QModelIndex &index) { - QString word=index.data().toString(); - QString prefix=completion.completionPrefix(); - - QString suffix=word.mid(prefix.length()); - - QTextCursor cursor=textCursor(); - cursor.insertText(suffix); - - completion.popup()->hide(); -} - -void CodeEdit::textModified_cb(bool ok) { - //printf("[CodeEdit::textModified_cb] Entered\n"); - if(text_modified_stop_ok) return; - emit textModified(ok); - //printf("[CodeEdit::textModified_cb] text_modified emit\n"); -} - -void CodeEdit::publicBlockBoundingRectList(QVector &list, int &first_line){ - - qreal pageBottom = viewport()->height(); - QPointF offset=contentOffset(); - QTextBlock block=firstVisibleBlock(); - first_line=block.blockNumber()+1; - qreal first_position=blockBoundingGeometry(block).topLeft().y(); - - for ( ; block.isValid(); block = block.next() ) - { - QRectF position=blockBoundingGeometry(block); - qreal y=position.topLeft().y()+offset.y()-first_position; - - if(y>pageBottom) break; - - list.append(y); - } -} diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/CodeEdit.h --- a/gui//src/CodeEdit.h Thu Apr 14 10:27:09 2011 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* Copyright (C) 2007 Alejandro Álvarez - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef CODEEDIT_H -#define CODEEDIT_H - -#include -#include -#include -#include "SyntaxHighlighter.h" -#include -#include -#include -#include "config.h" -#include - -struct UndoRedoItem -{ - int size, pos; - QString text; -}; - -/**TextEdit that supports highlited syntax and autocompletion.*/ -class CodeEdit: public QPlainTextEdit { - Q_OBJECT -public: - CodeEdit(QWidget *parent = 0); - ~CodeEdit(); - - /**List of y top left positions of bounding rects of each visible block of text. - * @param list List of top left positions. - * @param first_line First visible block in TextEdit. - */ - void publicBlockBoundingRectList(QVector &list, int &first_line); - -public slots: - void undo(); - void redo(); - void deleteSelection(); - void toggleBreakpoint(); - void buildAutoCompletionList(int pos, int charsRemoved, int charsAdded ); - void buildAutoCompletionList(); - void doCompletion(const QModelIndex &index); - void octaveCommandCompletion(); - void textModified_cb(bool ok); - -signals: - void toggleBreakpoint(int lineno); - - /** Dynamic help required. */ - void dynamicHelpRequired(const QString &text); - - /** Text modified. */ - void textModified(bool ok); - -protected: - SyntaxHighlighter *m_syntaxHighlighter; - QMenu contextMenu; - void contextMenuEvent(QContextMenuEvent *e); - bool event( QEvent * e ); - -private: - bool auto_indent; - QCompleter completion; - QStringListModel *completion_model; - QTimer braketsTimer, octaveCommandTimer, completionTimer; - QStringList completion_list; - int completionPosition; - - /** Builds auto completion list from block blockInit to blockEnd. */ - void buildAutoCompletionListSlide(QStringList &list, QTextBlock blockInit, QTextBlock blockEnd, QString word_to_complete, QString actual_word); - - bool text_modified_stop_ok; //Stops emit of text_modified signal - bool context_changed_ok; - - /** Automatic indention for while, if, for, switch, do and try statements. */ - bool automatic_indention_statement_ok; - /** Auto completion. */ - bool autocompletion_ok; -}; - -#endif // CODEEDIT_H diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/FileEditorMdiSubWindow.cpp --- a/gui//src/FileEditorMdiSubWindow.cpp Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/FileEditorMdiSubWindow.cpp Thu Apr 14 12:24:05 2011 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include FileEditorMdiSubWindow::FileEditorMdiSubWindow(QWidget *parent) : QMdiSubWindow(parent) { @@ -34,7 +35,7 @@ QFile file(fileName); file.open(QFile::ReadOnly); - m_codeEdit->setPlainText(file.readAll()); + m_simpleEditor->setPlainText(file.readAll()); file.close(); } @@ -59,7 +60,7 @@ m_fileName = ""; setWindowTitle(m_fileName); - m_codeEdit->setPlainText(""); + m_simpleEditor->setPlainText(""); } void FileEditorMdiSubWindow::saveFile() { @@ -67,12 +68,12 @@ QFile file(saveFileName); file.open(QFile::WriteOnly); - if(file.write(m_codeEdit->toPlainText().toLocal8Bit()) == -1) { + if(file.write(m_simpleEditor->toPlainText().toLocal8Bit()) == -1) { QMessageBox::warning(this, "Error Saving File", QString("The file could not be saved: %1.").arg(file.errorString())); } else { - m_codeEdit->document()->setModified(false); + m_simpleEditor->document()->setModified(false); } file.close(); @@ -102,12 +103,12 @@ QStyle *style = QApplication::style(); setWidget(new QWidget()); m_toolBar = new QToolBar(this); - m_codeEdit = new CodeEdit(this); + m_simpleEditor = new SimpleEditor(this); m_statusBar = new QStatusBar(this); - m_numberedTextView = new NumberedTextView(this, m_codeEdit); + m_numberedTextView = new NumberedCodeEdit(this, m_simpleEditor); - m_codeEdit->setFont(QFont("Courier")); - m_codeEdit->setLineWrapMode(QPlainTextEdit::NoWrap); + m_simpleEditor->setFont(QFont("Courier")); + m_simpleEditor->setLineWrapMode(QPlainTextEdit::NoWrap); QAction *newAction = new QAction(style->standardIcon(QStyle::SP_FileIcon), "", m_toolBar); @@ -131,8 +132,8 @@ widget()->setLayout(layout); connect(newAction, SIGNAL(triggered()), this, SLOT(newFile())); - connect(undoAction, SIGNAL(triggered()), m_codeEdit, SLOT(undo())); - connect(redoAction, SIGNAL(triggered()), m_codeEdit, SLOT(redo())); + connect(undoAction, SIGNAL(triggered()), m_simpleEditor, SLOT(undo())); + connect(redoAction, SIGNAL(triggered()), m_simpleEditor, SLOT(redo())); connect(saveAction, SIGNAL(triggered()), this, SLOT(saveFile())); connect(newAction, SIGNAL(hovered()), this, SLOT(showToolTipNew())); @@ -140,7 +141,7 @@ connect(redoAction, SIGNAL(hovered()), this, SLOT(showToolTipRedo())); connect(saveAction, SIGNAL(hovered()), this, SLOT(showToolTipSave())); - connect(m_codeEdit, SIGNAL(modificationChanged(bool)), this, SLOT(registerModified(bool))); + connect(m_simpleEditor, SIGNAL(modificationChanged(bool)), this, SLOT(registerModified(bool))); m_fileName = ""; setWindowTitle(m_fileName); diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/FileEditorMdiSubWindow.h --- a/gui//src/FileEditorMdiSubWindow.h Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/FileEditorMdiSubWindow.h Thu Apr 14 12:24:05 2011 +0200 @@ -22,7 +22,7 @@ #include #include #include -#include "CodeEdit.h" +#include "SimpleEditor.h" #include "NumberedCodeEdit.h" class FileEditorMdiSubWindow : public QMdiSubWindow { @@ -44,8 +44,8 @@ private: void construct(); QToolBar *m_toolBar; - CodeEdit *m_codeEdit; - NumberedTextView *m_numberedTextView; + SimpleEditor *m_simpleEditor; + NumberedCodeEdit *m_numberedTextView; QStatusBar *m_statusBar; QString m_fileName; bool m_modified; diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/MainWindow.cpp --- a/gui//src/MainWindow.cpp Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/MainWindow.cpp Thu Apr 14 12:24:05 2011 +0200 @@ -63,7 +63,6 @@ QSettings settings(m_settingsFile, QSettings::IniFormat); restoreGeometry(settings.value("MainWindow/geometry").toByteArray()); restoreState(settings.value("MainWindow/windowState").toByteArray()); - } void MainWindow::writeSettings() { diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/MainWindow.h --- a/gui//src/MainWindow.h Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/MainWindow.h Thu Apr 14 12:24:05 2011 +0200 @@ -30,7 +30,7 @@ #include "VariablesDockWidget.h" #include "HistoryDockWidget.h" #include "FilesDockWidget.h" -#include "CodeEdit.h" +#include "SimpleEditor.h" #include "BrowserWidget.h" // Octave includes diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/NumberedCodeEdit.cpp --- a/gui//src/NumberedCodeEdit.cpp Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/NumberedCodeEdit.cpp Thu Apr 14 12:24:05 2011 +0200 @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include "NumberedCodeEdit.h" #include "config.h" @@ -35,10 +38,9 @@ { // Make room for 4 digits and the breakpoint icon setFixedWidth( fontMetrics().width( QString("0000") + 10 + 32 ) ); - stopMarker = QPixmap(); //QString(ICON_PATH) + "/stop.png" ); - currentMarker = QPixmap(); // QString(ICON_PATH) + "/bookmark.png" ); - bugMarker = QPixmap(); // QString(ICON_PATH) + "/bug.png" ); - setFont(QFont("Courier")); + stopMarker = QPixmap();// QString(ICON_PATH) + "/stop.png" ); + currentMarker = QPixmap();// QString(ICON_PATH) + "/bookmark.png" ); + bugMarker = QPixmap();// QString(ICON_PATH) + "/bug.png" ); } NumberBar::~NumberBar() @@ -70,7 +72,7 @@ update(); } -void NumberBar::setTextEdit( CodeEdit *edit ) +void NumberBar::setTextEdit( SimpleEditor *edit ) { this->edit = edit; setFixedWidth( edit->fontMetrics().width( QString("0000") + 10 + 32 ) ); @@ -87,7 +89,7 @@ edit->publicBlockBoundingRectList(lines_list, first_line_no); const QFontMetrics fm = edit->fontMetrics(); - const int ascent = fontMetrics().ascent(); // height = ascent + descent + 1 + const int ascent = fontMetrics().ascent(); // height = ascent + descent QPainter p(this); p.setPen(palette().windowText().color()); @@ -107,7 +109,7 @@ lineCount=first_line_no+i; const QString txt = QString::number( lineCount ); - p.drawText( width() - fm.width(txt) - 2, position_y+ascent, txt ); + p.drawText( width() - fm.width(txt)- 2, position_y+ascent, txt ); // Bug marker if ( bugLine == lineCount ) { @@ -127,6 +129,55 @@ currentRect = QRect( 1, position_y, currentMarker.width(), currentMarker.height() ); } } + + /* + + int contentsY = edit->verticalScrollBar()->value(); + qreal pageBottom = contentsY + edit->viewport()->height(); + const QFontMetrics fm = fontMetrics(); + const int ascent = fontMetrics().ascent() + 1; // height = ascent + descent + 1 + int lineCount = 1; + + QPainter p(this); + p.setPen(palette().windowText().color()); + + bugRect = QRect(); + stopRect = QRect(); + currentRect = QRect(); + + for ( QTextBlock block = edit->document()->begin(); + block.isValid(); block = block.next(), ++lineCount ) { + + const QRectF boundingRect = edit->publicBlockBoundingRect( block ); + + QPointF position = boundingRect.topLeft(); + if ( position.y() + boundingRect.height() < contentsY ) + continue; + if ( position.y() > pageBottom ) + break; + + const QString txt = QString::number( lineCount ); + p.drawText( width() - fm.width(txt), qRound( position.y() ) - contentsY + ascent, txt ); + + // Bug marker + if ( bugLine == lineCount ) { + p.drawPixmap( 1, qRound( position.y() ) - contentsY, bugMarker ); + bugRect = QRect( 1, qRound( position.y() ) - contentsY, bugMarker.width(), bugMarker.height() ); + } + + // Stop marker + if ( breakpoints.contains(lineCount) ) { + p.drawPixmap( 19, qRound( position.y() ) - contentsY, stopMarker ); + stopRect = QRect( 19, qRound( position.y() ) - contentsY, stopMarker.width(), stopMarker.height() ); + } + + // Current line marker + if ( currentLine == lineCount ) { + p.drawPixmap( 19, qRound( position.y() ) - contentsY, currentMarker ); + currentRect = QRect( 19, qRound( position.y() ) - contentsY, currentMarker.width(), currentMarker.height() ); + } + } + */ } bool NumberBar::event( QEvent *event ) @@ -155,7 +206,7 @@ -NumberedTextView::NumberedTextView( QWidget *parent, CodeEdit *textEdit ) +NumberedCodeEdit::NumberedCodeEdit( QWidget *parent, SimpleEditor *textEdit ) : QFrame( parent ) { setFrameStyle( QFrame::StyledPanel | QFrame::Sunken ); @@ -193,16 +244,16 @@ vbox->addLayout(messages_layout); messages_layout->setSpacing( 0 ); messages_layout->setMargin( 0 ); -} + } -NumberedTextView::~NumberedTextView() +NumberedCodeEdit::~NumberedCodeEdit() { hide(); //printf("Borrado ntv\n"); } -void NumberedTextView::setCurrentLine( int lineno ) +void NumberedCodeEdit::setCurrentLine( int lineno ) { currentLine = lineno; if(numbers!=NULL) numbers->setCurrentLine( lineno ); @@ -223,20 +274,50 @@ textChanged( 0, 0, 1 ); } -void NumberedTextView::toggleBreakpoint( int lineno ) +void NumberedCodeEdit::toggleBreakpoint( int lineno ) { if(numbers!=NULL) numbers->toggleBreakpoint( lineno ); } -void NumberedTextView::setBugLine( int lineno ) +void NumberedCodeEdit::setBugLine( int lineno ) { if(numbers!=NULL) numbers->setBugLine( lineno ); } -void NumberedTextView::textChanged( int /*pos*/, int removed, int added ) +void NumberedCodeEdit::textChanged( int /*pos*/, int removed, int added ) { + //Q_UNUSED( pos ); + if ( removed == 0 && added == 0 ) return; + + //QTextBlock block = highlight.block(); + //QTextBlock block = view->document()->begin(); + //QTextBlockFormat fmt = block.blockFormat(); + //QColor bg = view->palette().base().color(); + //fmt.setBackground( bg ); + //highlight.setBlockFormat( fmt ); + /* + QTextBlockFormat fmt; + + int lineCount = 1; + for ( QTextBlock block = view->document()->begin(); + block.isValid() && block!=view->document()->end(); block = block.next(), ++lineCount ) { + + if ( lineCount == currentLine ) + { + fmt = block.blockFormat(); + QColor bg = view->palette().highlight().color(); + fmt.setBackground( bg ); + + highlight = QTextCursor( block ); + highlight.movePosition( QTextCursor::EndOfBlock, QTextCursor::KeepAnchor ); + highlight.setBlockFormat( fmt ); + + break; + } + } + */ if( !textModifiedOk && view->document()->isModified() ) { @@ -245,7 +326,7 @@ } } -bool NumberedTextView::eventFilter( QObject *obj, QEvent *event ) +bool NumberedCodeEdit::eventFilter( QObject *obj, QEvent *event ) { if ( obj != view ) return QFrame::eventFilter(obj, event); @@ -260,48 +341,74 @@ QString word = cursor.selectedText(); emit mouseHover( word ); emit mouseHover( helpEvent->pos(), word ); + + // QToolTip::showText( helpEvent->globalPos(), word ); // For testing } return false; } -QList *NumberedTextView::getBreakpoints() +QList *NumberedCodeEdit::getBreakpoints() { QList *br=NULL; if(numbers!=NULL) br=numbers->getBreakpoints(); return br; } -void NumberedTextView::open(QString path) +void NumberedCodeEdit::open(QString path) { FILE *fl; fl = fopen(path.toLocal8Bit().constData(), "rt"); if(fl) { - filePath = path; - QTextStream stream(fl); - textEdit()->document()->setPlainText(stream.readAll()); - fclose(fl); - textModifiedOk=false; - textEdit()->document()->setModified(false); + fclose(fl); + filePath = path; + + textEdit()->load(path); + + textModifiedOk=false; + textEdit()->document()->setModified(false); }else{ throw path; } } -void NumberedTextView::save(QString path) +bool NumberedCodeEdit::save(QString path) { FILE *fl; - if(path.isEmpty()) - path = filePath; - else - filePath = path; - + if(path.isEmpty()) path = filePath; + QRegExp re("[A-Za-z_][A-Za-z0-9_]*\\.m"); + + if( ! re.exactMatch( QFileInfo(path).fileName() ) ) + { + QMessageBox msgBox; + msgBox.setText( tr("This file name is not valid.") ); + msgBox.setInformativeText(tr("Octave doesn't understand this file name:\n")+path+tr("\nPlease, change it.\n Do you want to save your changes?")); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Save); + int ret = msgBox.exec(); + switch (ret) + { + case QMessageBox::Save: + // Save was clicked + break; + case QMessageBox::Cancel: + // Cancel was clicked + return false; + break; + default: + // should never be reached + break; + } + } + + fl = fopen(path.toLocal8Bit().constData(), "wt"); if(fl) { + filePath = path; QTextStream *stream = new QTextStream(fl); (*stream) << textEdit()->document()->toPlainText(); delete stream; @@ -309,37 +416,47 @@ textModifiedOk=false; view->document()->setModified(false); }else{ - throw path; + return false; } - QString repository=path+"~~"; - QString command("simplercs \""+repository+"\" \""+path+"\""); - QProcess::startDetached(command); - //QProcess::execute(command); - + /*if(get_config("simple_rcs")=="true") + { + QString repository=path+"~~"; + QString command("simplercs \""+repository+"\" \""+path+"\""); + QProcess::startDetached(command); + //QProcess::execute(command); + printf("[NumberedTextView::save] Comando: %s\n", command.toLocal8Bit().data() ); + } + else + { + //printf("[NumberedTextView::save] No rcs\n"); + }*/ + + return true; } -QString NumberedTextView::path() +QString NumberedCodeEdit::path() { return filePath; } -void NumberedTextView::setPath(QString path) +void NumberedCodeEdit::setPath(QString path) { filePath=path; + textEdit()->setFile(path); } -void NumberedTextView::setModified(bool modify) +void NumberedCodeEdit::setModified(bool modify) { textModifiedOk=modify; } -bool NumberedTextView::modified() +bool NumberedCodeEdit::modified() { return textModifiedOk; } -void NumberedTextView::cursor_moved_cb() +void NumberedCodeEdit::cursor_moved_cb() { QTextCursor cursor=view->textCursor(); QTextBlock actual_block=cursor.block(); @@ -347,7 +464,6 @@ QTextBlock block = view->document()->begin(); for ( ;block.isValid() && actual_block!=block; block = block.next()) lineCount++ ; - } static QString startLineInsertText(QString str, QString textToInsert) @@ -419,7 +535,7 @@ return list.join("\n"); } -void NumberedTextView::indent() +void NumberedCodeEdit::indent() { //QTextDocument *doc=textEdit()->document(); @@ -436,7 +552,7 @@ textEdit()->setTextCursor(cursor); } -void NumberedTextView::unindent() +void NumberedCodeEdit::unindent() { //QTextDocument *doc=textEdit()->document(); @@ -455,7 +571,7 @@ textEdit()->setTextCursor(cursor); } -void NumberedTextView::comment() +void NumberedCodeEdit::comment() { //QTextDocument *doc=textEdit()->document(); @@ -472,7 +588,7 @@ textEdit()->setTextCursor(cursor); } -void NumberedTextView::uncomment() +void NumberedCodeEdit::uncomment() { //QTextDocument *doc=textEdit()->document(); diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/NumberedCodeEdit.h --- a/gui//src/NumberedCodeEdit.h Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/NumberedCodeEdit.h Thu Apr 14 12:24:05 2011 +0200 @@ -27,9 +27,9 @@ #include #include #include -#include "CodeEdit.h" +#include "SimpleEditor.h" -class CodeEdit; +class SimpleEditor; class QHBoxLayout; /** @@ -48,14 +48,14 @@ void toggleBreakpoint( int lineno ); QList *getBreakpoints(); - void setTextEdit( CodeEdit *edit ); + void setTextEdit( SimpleEditor *edit ); void paintEvent( QPaintEvent *ev ); protected: bool event( QEvent *ev ); private: - CodeEdit *edit; + SimpleEditor *edit; QPixmap stopMarker; QPixmap currentMarker; QPixmap bugMarker; @@ -70,18 +70,20 @@ /** * Displays a CodeEdit with line numbers. */ -class NumberedTextView : public QFrame +class NumberedCodeEdit : public QFrame { Q_OBJECT public: - NumberedTextView( QWidget *parent = 0 , CodeEdit *textEdit=new CodeEdit() ); - ~NumberedTextView(); + NumberedCodeEdit( QWidget *parent = 0 , SimpleEditor *textEdit=new SimpleEditor() ); + ~NumberedCodeEdit(); QList *getBreakpoints(); void open(QString path); - void save(QString path = QString()); + + /**Saves file to path. @return true if all is OK.*/ + bool save(QString path = QString()); QString path(); void setPath(QString path); @@ -90,7 +92,7 @@ void setModified(bool modify); /** Returns the CodeEdit of the main view. */ - CodeEdit *textEdit() const { return view; } + SimpleEditor *textEdit() const { return view; } /** * Sets the line that should have the current line indicator. @@ -151,7 +153,8 @@ private: QString filePath; - CodeEdit *view; + QLabel *line_column_label; + SimpleEditor *view; NumberBar *numbers; QHBoxLayout *hbox; QVBoxLayout *vbox; diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/SimpleEditor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui//src/SimpleEditor.cpp Thu Apr 14 12:24:05 2011 +0200 @@ -0,0 +1,363 @@ +/* Copyright (C) 2010 P.L. Lucas + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "SimpleEditor.h" +#include +#include +#include +#include +#include + +SimpleEditor::SimpleEditor(QWidget *parent):QPlainTextEdit(parent) +{ + syntaxHighlighter=NULL; + firtsTimeUsedOk=true; + completerModel=new QStringListModel (); + completer= new QCompleter(completerModel, this); + completer->setCompletionMode(QCompleter::PopupCompletion); + completer->setWidget(this); + connect(completer, SIGNAL(activated ( const QString &)), this, SLOT(activated ( const QString &))); + //if(get_config("bracketsMatch")!="false") + connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChangedCallBack())); + //if((get_config("autoCompletion")!="false")) + connect(document(), SIGNAL(contentsChange(int, int, int)), this, SLOT(autoComplete(int, int, int))); + + auto_indent=true;//("false"!=get_config("autoindent")); + automatic_indention_statement_ok =true;// (get_config("autoindent_statements")=="true"); + + //Set editor's font + + QFont text_edit_font; + QString font_name="Courier";//get_config("textEditFont"); + QString font_size="10";//get_config("textEditFontSize"); + if(font_name.isEmpty()) + { + font_name=text_edit_font.family(); + } + if(font_size.isEmpty()) + { + font_size=QString::number(text_edit_font.pointSize()); + } + text_edit_font.setFamily(font_name); + text_edit_font.setPointSize(font_size.toInt()); + setFont(text_edit_font); +} + +void SimpleEditor::loadSyntaxXMLDescription() +{ + QString installPath=QString("syntax_files")+QDir::separator(); + QFileInfo file(fileName); + QString suffix=file.suffix(); + + if(comands_completion_list.isEmpty()) + { + QString home=QDir::home().path()+QDir::separator()+".qtoctave"+QDir::separator()+"commands.txt"; + + QFile file(home); + + if (file.open(QFile::ReadOnly)) + { + char buf[1024]; + + while(file.readLine(buf, sizeof(buf))>=0) + { + comands_completion_list.append(QString(buf).trimmed()); + } + + file.close(); + } + } + + //if(get_config("syntaxHighlighting")!="true") return; + + QFileInfo xml(installPath+suffix+".xml"); + if(xml.exists()) + { + printf("[SimpleEditor::loadSyntaxXMLDescription] Loading syntax\n"); + syntaxHighlighter=new SyntaxHighlighter( document() ); + syntaxHighlighter->load(xml.absoluteFilePath()); + syntaxHighlighter->setDocument(document()); + } +} + +bool SimpleEditor::load(QString file) +{ + if(file.isEmpty()) + { + setPlainText(""); + fileName=file; + return true; + } + + FILE *input=fopen(file.toLocal8Bit().data(),"r"); + if(input==NULL) return false; + fclose(input); + QFile in(file); + if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) + return false; + QByteArray data=in.readAll(); + + setPlainText( QString::fromLocal8Bit(data) ); + fileName=file; + + firtsTimeUsedOk=false; + + loadSyntaxXMLDescription(); + + return true; +} + +bool SimpleEditor::save() +{ + QFile::remove(fileName+"~"); + QFile::copy(fileName, fileName+"~"); + FILE *out=fopen(fileName.toLocal8Bit().data(),"w"); + if(out==NULL) return false; + fprintf( out, "%s", toPlainText().toLocal8Bit().data() ); + fclose(out); + document()->setModified(false); + return true; +} + +void SimpleEditor::keyPressEvent(QKeyEvent * e) +{ + //printf("%d %s\n",e->key(), e->text().toLocal8Bit().data()); + + //In all cases completer popup must been hided. + if(e->key()!=Qt::Key_Return && e->key()!=Qt::Key_Enter ) + { + QAbstractItemView *view=completer->popup(); + if(view->isVisible()) view->hide(); + //completer->setWidget(NULL); + } + + if(e->key()==Qt::Key_Return || e->key()==Qt::Key_Enter ) + { + QAbstractItemView *view=completer->popup(); + if(view->isVisible()) + { + QString word=view->currentIndex().data().toString(); + if( word.isEmpty() ) word=completer->currentCompletion(); + activated( word ); + return; + } + else if(auto_indent) + { + QTextCursor cursor=textCursor(); + QString line=cursor.block().text(); + QString line2=line; + for(int i=0;ikey()==(Qt::Key_B) && Qt::ControlModifier==e->modifiers() ) + //{ + // autoComplete(); + // return; + //} + else if(e->key()==Qt::Key_Tab) + { + QTextCursor cursor=textCursor(); + int start=cursor.selectionStart(); + int end=cursor.selectionEnd(); + if(start==end) + { + QPlainTextEdit::keyPressEvent(e); + return; + } + cursor.beginEditBlock(); + cursor.setPosition(end); + end=cursor.blockNumber(); + cursor.setPosition(start); + cursor.movePosition(QTextCursor::StartOfBlock); + while(true) + { + cursor.insertText("\t"); + if(cursor.blockNumber()>=end) break; + cursor.movePosition(QTextCursor::NextBlock); + } + cursor.endEditBlock(); + } + else if(e->key()==Qt::Key_Backtab ) + { + QTextCursor cursor=textCursor(); + int start=cursor.selectionStart(); + int end=cursor.selectionEnd(); + if(start==end) + { + QPlainTextEdit::keyPressEvent(e); + return; + } + cursor.beginEditBlock(); + cursor.setPosition(end); + end=cursor.blockNumber(); + cursor.setPosition(start); + cursor.movePosition(QTextCursor::StartOfBlock); + while( true ) + { + QString line=cursor.block().text(); + if(line.length()>0 && (line[0]==' ' || line[0] + =='\t') ) + { + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + cursor.removeSelectedText(); + } + if(cursor.blockNumber()>=end) break; + cursor.movePosition(QTextCursor::NextBlock); + cursor.movePosition(QTextCursor::StartOfBlock); + } + cursor.endEditBlock(); + } + else + { + if( e->key()==(Qt::Key_B) && Qt::ControlModifier==e->modifiers() ) + { + autoComplete(0); + return; + } + + QPlainTextEdit::keyPressEvent(e); + + } + + +} + +void SimpleEditor::setCharFormat(QTextCharFormat charFormat) +{ + this->charFormat=charFormat; + QTextCursor cursor=textCursor(); + cursor.movePosition(QTextCursor::Start); + cursor.setCharFormat(charFormat); + cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); + setFont(charFormat.font()); + + QFontMetrics fm(charFormat.font()); + int textWidthInPixels = fm.width(" "); + setTabStopWidth(textWidthInPixels); +} + +void SimpleEditor::activated( const QString & text ) +{ + QAbstractItemView *view=completer->popup(); + QTextCursor cursor=textCursor(); + cursor.movePosition( + QTextCursor::PreviousWord, QTextCursor::KeepAnchor); + cursor.insertText(text); + view->hide(); +} + +void SimpleEditor::autoComplete(int position, int charsRemoved, int charsAdded) +{ + //printf("[SimpleEditor::autoComplete] charsAdded=%d\n", charsAdded); + if(charsAdded==1) + autoComplete(); +} + +void SimpleEditor::autoComplete(int size) +{ + QTextCursor cursor=textCursor(); + + cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor); + + //printf("[SimpleEditor::autoComplete] >%s<\n", cursor.selectedText().toLocal8Bit().data()); + + if( cursor.selectedText().endsWith(" ") || cursor.selectedText().trimmed().length()setStringList( list ); + + completer->setCompletionPrefix(cursor.selectedText()); + + //printf("[SimpleEditor::autoComplete] >%d<\n", completer->completionCount()); + + if (completer->completionCount()>0 ) + { + //completer->setWidget(this); + QRect r=cursorRect(cursor); + r.setWidth(200); + completer->complete(r); + } +} + + +QString SimpleEditor::getFileName() +{ + return fileName; +} + + +void SimpleEditor::setFile(QString file) +{ + fileName=file; + loadSyntaxXMLDescription(); +} + + +void SimpleEditor::cursorPositionChangedCallBack() +{ + //Hightlight brackets + if(syntaxHighlighter!=NULL) + syntaxHighlighter->setFormatPairBrackets(this); +} + +void SimpleEditor::publicBlockBoundingRectList(QVector &list, int &first_line) +{ + qreal pageBottom = /*viewport()->*/height(); + QPointF offset=contentOffset(); + QTextBlock block=firstVisibleBlock(); + first_line=block.blockNumber()+1; + qreal first_position=blockBoundingGeometry(block).topLeft().y(); + + for ( ; block.isValid(); block = block.next() ) + { + QRectF position=blockBoundingGeometry(block); + qreal y=position.topLeft().y()+offset.y()-first_position; + + if(y>pageBottom) break; + + list.append(y); + } +} + diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/SimpleEditor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui//src/SimpleEditor.h Thu Apr 14 12:24:05 2011 +0200 @@ -0,0 +1,87 @@ +#ifndef __SIMPLEEDITOR_H__ +/* Copyright (C) 2010 P.L. Lucas + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#define __SIMPLEEDITOR_H__ + +#include +#include +#include +#include "SyntaxHighlighter.h" + +class SimpleEditor : public QPlainTextEdit +{ + Q_OBJECT + QString fileName; + QTextCharFormat charFormat; + QCompleter *completer; + QStringListModel *completerModel; + SyntaxHighlighter *syntaxHighlighter; + QStringList comands_completion_list; + + bool auto_indent, automatic_indention_statement_ok; + + void loadSyntaxXMLDescription(); + + public: + bool firtsTimeUsedOk; + + SimpleEditor(QWidget * parent = 0); + + bool load(QString file); + bool save(); + QString getFileName(); + void setFile(QString file); + + void setCharFormat(QTextCharFormat charFormat); + + + + /**List of y top left positions of bounding rects of each visible block of text. + * @param list List of top left positions. + * @param first_line First visible block in TextEdit. + */ + void publicBlockBoundingRectList(QVector &list, int &first_line); + + public slots: + + void activated( const QString & text ); + void cursorPositionChangedCallBack(); + void autoComplete(int size=3); + void autoComplete(int position, int charsRemoved, int charsAdded); + + protected: + virtual void keyPressEvent(QKeyEvent * e); + //virtual void focusInEvent(QFocusEvent * event); + + + signals: + /**Dinamic help required.*/ + void dynamic_help_required(const QString &text); + + ///**Text modified.*/ + //void text_modified(bool ok); + + //void toggleBreakpoint(int lineno); + + //void focusChanged(QWidget *); +} +; +#endif + diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/SyntaxHighlighter.cpp --- a/gui//src/SyntaxHighlighter.cpp Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/SyntaxHighlighter.cpp Thu Apr 14 12:24:05 2011 +0200 @@ -1,4 +1,4 @@ -/* Copyright (C) 2006-2008 P.L. Lucas +/* Copyright (C) 2010 P.L. Lucas * * 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 @@ -16,453 +16,503 @@ * Boston, MA 02111-1307, USA. */ -#include "SyntaxHighlighter.h" -#include -#include -#include -#include -#include -#include - -QList SyntaxHighlighter::rules; -QStringList SyntaxHighlighter::octave_comands; -/*** Xml Handler ***/ -class SyntaxXmlHandler:public QXmlDefaultHandler { -private: - SyntaxHighlighter *syntax; - QString type_name, text; - struct Tag - { - QString tag, type; - QStringList items; - QList childs; - }; - QList stack; - QStringList *octave_comands; +#include "SyntaxHighlighter.h" + -public: - // Constructor - SyntaxXmlHandler(SyntaxHighlighter *s, QStringList *octave_comands) - : QXmlDefaultHandler(), syntax(s) { - this->octave_comands=octave_comands; - } - - bool startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, - const QString &qname, const QXmlAttributes &atts) { - Tag tag; - tag.tag=qname; +#include +#include +#include +#include - if(qname == "list") - {// List block. Get the type name. - tag.type = atts.value("name").trimmed(); - if(tag.type=="functions") - { - tag.items << (*octave_comands); - } - } - //else if(qname == "item") - //{// Item. Next string is an item. - //} - else if(qname == "comment") - {// Comments. - syntax->setComment(atts.value("start"), "$", atts.value("name")); - } - - stack.append(tag); - return true; - } +SyntaxHighlighter::SyntaxHighlighter(QObject * parent):QSyntaxHighlighter(parent) +{ +} - bool characters(const QString &ch) { - text+=ch; - return true; - } - - bool endElement(const QString & /*namespaceURI*/, - const QString & /*localName*/, - const QString & qname ) { - Tag tag; - - if(stack.isEmpty()) return true; - - tag=stack.last(); - stack.removeLast(); - - if(tag.tag!=qname) { - printf("Error reading XML syntax\n"); - return false; - } - - if(qname == "list") {// List block. Get the type name. - if(stack.last().tag=="list") { - stack.last().childs.append(tag); - } else { - syntax->setItem(tag.items.join("|"), tag.type); - for(int i=0;isetItem(tag.childs[i].items.join("|"), tag.childs[i].type,tag.type); - } - } - } else if(qname == "item") { - // Item. Next string is an item. - if(! text.trimmed().isEmpty() ) - stack.last().items << text.trimmed(); - } - - text=""; - return true; - } -}; - -/*** Block data ***/ -class BlockData:public QTextBlockUserData { -public: - BlockData() {braket_start_pos=braket_end_pos=-1;} - ~BlockData (){} - int braket_start_pos, braket_end_pos; - QHash bracket; -}; - -/*** Syntax ***/ -SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent) - : QSyntaxHighlighter(parent) { - QTextCharFormat f; +bool SyntaxHighlighter::load(QString file) +{ + QXmlStreamReader xml; + QStack stack; + QFile fileDevice(file); + if (!fileDevice.open(QFile::ReadOnly | QFile::Text)) { + printf("Error al abrir el archivo\n"); + return false; + } + + xml.setDevice(&fileDevice); + + QMap values; + + QVector xmlMainItems; + xmlMainItems << "item" << "block" << "bracket"; + + int ruleOrder=0; + + while (!xml.atEnd()) + { + QXmlStreamReader::TokenType tokenType=xml.readNext(); + switch(tokenType) + { + case QXmlStreamReader::StartElement: + if(xml.name()!="syntax") + { + if( xmlMainItems.contains(xml.name().toString()) ) + stack.push(xml.name().toString()); + else + values[xml.name().toString()]=xml.readElementText().trimmed(); + } + break; + case QXmlStreamReader::EndElement: + if(stack.isEmpty()) break; + QString name=stack.top(); + if(name==xml.name()) stack.pop(); + if(stack.isEmpty()) + { + QTextCharFormat format; + if(values.contains("bold") && values["bold"]=="true") format.setFontWeight(QFont::Bold); + if(values.contains("underline") && values["underline"]=="true") format.setFontUnderline(true); + if(values.contains("italic") && values["italic"]=="true") format.setFontItalic(true); + if(values.contains("foreground")) format.setForeground(QBrush(QColor(values["foreground"]))); + if(values.contains("background")) format.setBackground(QBrush(QColor(values["background"]))); + if(name=="item") + { + HighlightingRule rule; + rule.format=format; + rule.pattern=QRegExp(values["pattern"]); + rule.ruleOrder=ruleOrder++; + highlightingRules.append(rule); + values.clear(); + } + else if(name=="block" || name=="bracket") + { + HighlightingBlockRule rule; + rule.format=format; + rule.startPattern=QRegExp(values["startPattern"]); + rule.endPattern=QRegExp(values["endPattern"]); + rule.ruleOrder=ruleOrder++; + if(name=="block") highlightingBlockRules.append(rule); + else highlightingBracketsRules.append(rule); //Bracket rule + values.clear(); + } + } + break; + } + } + if (xml.hasError()) + { + // do error handling + printf("Error %s: %ld:%ld %s\n", file.toLocal8Bit().data(), xml.lineNumber(), xml.columnNumber(), xml.errorString().toLocal8Bit().data() ); + return false; + } + + return true; +} - QFont text_edit_font; - QString font_name="Monospace";//get_config("textEditFont"); - QString font_size="10";//get_config("textEditFontSize"); - if(font_name.isEmpty()) { - font_name=text_edit_font.family(); - } - - if(font_size.isEmpty()) { - font_size=QString::number(text_edit_font.pointSize()); - } - - text_edit_font.setFamily(font_name); - text_edit_font.setPointSize(font_size.toInt()); - - f.setFont(text_edit_font); - f.setFontWeight(QFont::Bold); - _format["keywords"] = f; - _format["commands"] = f; - f.setFontWeight(QFont::Normal); - f.setForeground(Qt::darkGreen); - _format["builtin"] = f; - f.setForeground(Qt::blue); - _format["functions"] = f; - // operators - f.setForeground(Qt::black); - _format["variables"] = f; - f.setForeground(Qt::darkMagenta); - _format["numbers"] = f; - f.setForeground(Qt::red); - _format["strings"] = f; - // delimiters - f.setForeground(Qt::darkGray); - _format["singleLine"] = f; - //Brackets matched - f.setForeground(Qt::black); - //f.setFontWeight(QFont::Bold); - f.setBackground(Qt::yellow); - _format["bracket match"]=f; - - active_ok=true; - - braketsMacth_ok=false; - - //printf("Syntax Builded\n"); - - //Add rules to vectors to help to highlightBlock method - __re.clear(); - __i_aux.clear(); - for(int n=0;npattern); - __i_aux.append(-1); - //printf("%s %d %d\n", rules.at(n)->type.toLocal8Bit().data(), __re.size(), __i_aux[n]); - } +SyntaxHighlighter::Rule1st SyntaxHighlighter::highlight1stRule(const QString & text, int startIndex) +{ + Rule1st rule1st; + rule1st.startIndex=text.length(); + rule1st.rule=-1; + + for(int i=0; ipattern); + int index = rule->lastFound; + //printf("[Syntax::highlight1stRule] i=%d pos=%d startIndex=%d\n", i, index, startIndex); + if(index>-1 && indexlastFound = index = expression->indexIn(text, startIndex); + } + if ( index>-1 && indexmatchedLength(); + rule1st.rule=i; + rule1st.ruleOrder=rule->ruleOrder; + } + + if(index==startIndex) break; + } + + if(rule1st.rule==-1) rule1st.startIndex=-1; + + return rule1st; } -SyntaxHighlighter::~SyntaxHighlighter() { - //foreach(Rule *value, rules_map) - //{ - // delete value; - //} +SyntaxHighlighter::Rule1st SyntaxHighlighter::highlight1stBlockRule(const QString & text, int startIndex) +{ + Rule1st rule1st; + rule1st.startIndex=text.length(); + rule1st.rule=-1; + + for(int i=0; i-1 && indexbrackets + */ +static void insertInOrder(BlockData *blockData, BlockData::Bracket &bracket) +{ + if(blockData->brackets.isEmpty()) blockData->brackets.append(bracket); + else + { + int j=0; + + for(;jbrackets.size();j++) + { + if(blockData->brackets[j].pos>bracket.pos) + { + blockData->brackets.insert(j,bracket); + break; + } + } + if(j>=blockData->brackets.size()) + { + blockData->brackets.append(bracket); + } + } +} + - //This line is added because sometimes Qt try rehighlight text at destroy - setDocument(NULL); +void SyntaxHighlighter::findBrackets(const QString & text, int start, int end, BlockData *blockData) +{ + //blockData->brackets.clear(); + + if( end<0 || end>text.length() ) end=text.length(); + + if(start>end) return; + + for(int i=0; i-1 && index-1 && index=0) { - octave_comands.append(QString(buf).trimmed()); - } - file.close(); - } - } - - //rules = &(instances[path]); - if(rules.isEmpty()) { - // Load from file - FILE *fl; - - fl = fopen(path.toLocal8Bit().constData(), "rt"); - if(!fl) { - std::cerr << "[Syntax::load] Can not load the syntax file" << std::endl; - return; - } - - QFile file(path); - QXmlSimpleReader parser; - QXmlInputSource source(&file); - SyntaxXmlHandler handler(this, &octave_comands); - - file.open(fl, QIODevice::ReadOnly); - - parser.setContentHandler(&handler); - parser.setErrorHandler(&handler); - - parser.parse(&source); - - file.close(); - - fclose(fl); - - std::cout << "[Sytax::load] " - << path.toLocal8Bit().constData() - << " loaded" - << std::endl; - } +int SyntaxHighlighter::blockRuleSetFormat(const QString & text, Rule1st rule1st) +{ + HighlightingBlockRule rule=highlightingBlockRules[rule1st.rule]; + + int endIndex = rule.endPattern.indexIn(text, rule1st.startIndex); + int commentLength; + if (endIndex == -1) + { + setCurrentBlockState(rule1st.rule); + commentLength = text.length() - rule1st.startIndex; + setFormat(rule1st.startIndex, commentLength, rule.format); + return text.length(); + } + else + { + commentLength = endIndex - rule1st.startIndex + + rule.endPattern.matchedLength(); + setFormat(rule1st.startIndex, commentLength, rule.format); + + return endIndex+1; + } } -void SyntaxHighlighter::setItem(const QString &item, const QString &type, const QString parent) { - Rule *r; - if(!item.isEmpty()) { - r=new Rule; - r->pattern = QRegExp(item); - r->type = type; - r->format = _format[type]; - rules_map[type]=r; - if(parent.isEmpty() || !rules_map.contains(parent)) - rules.push_back(r); - else - rules_map[parent]->rules.push_back(r); - } -} + +void SyntaxHighlighter::highlightBlock ( const QString & text ) +{ + + setCurrentBlockState(-1); + + int startIndex = 0; + + //Checks previous block state + if (previousBlockState() >= 0) + { + Rule1st rule1st; + rule1st.rule=previousBlockState(); + rule1st.startIndex=0; + + startIndex=blockRuleSetFormat(text,rule1st); + + //TODO: Posible fallo al establecer el estado del bloque + + if(startIndex==text.length()) return; + } + + //Gets BlockData + BlockData *blockData=new BlockData(); + + //Finds first rule to apply. -void SyntaxHighlighter::setComment(const QString &start, const QString &end, const QString &type) { - Rule *r; - if(!type.isEmpty()) { - r=new Rule; - r->pattern = QRegExp(/*QString("^") +*/ start + ".*" + end); - r->type = type; - r->format = _format[type]; - rules_map[type]=r; - rules.push_back(r); - } -} - -void SyntaxHighlighter::setType(const QString &type, const QTextCharFormat &f) { - _format[type] = f; + Rule1st rule1st, blockRule1st; + + //Find initial matches + for(int i=0; ipattern); + int index = expression->indexIn(text, startIndex); + rule->lastFound = index; + //printf("[Syntax::highlightBlock] index=%d pos=%d \n", index, expression->pos(0)); + } + + //printf("[Syntax::highlightBlock] Find initial matches \n"); + + rule1st=highlight1stRule( text, startIndex); + blockRule1st=highlight1stBlockRule( text, startIndex); + + //if(rule1st.rule<0 && blockRule1st.rule<0) + //{ + // findBrackets(text, startIndex, -1, blockData); + //} + //else + while(rule1st.rule>=0 || blockRule1st.rule>=0) + { + if(rule1st.rule>=0 && blockRule1st.rule>=0) + { + if + ( + rule1st.startIndex=0) + { + findBrackets(text, startIndex, rule1st.startIndex, blockData); + startIndex=ruleSetFormat(rule1st); + rule1st=highlight1stRule( text, startIndex); + } + else + { + findBrackets(text, startIndex, blockRule1st.startIndex, blockData); + startIndex=blockRuleSetFormat(text,blockRule1st); + blockRule1st=highlight1stBlockRule( text, startIndex); + } + + //Finds next 1st rule + //rule1st=highlight1stRule( text, startIndex); + //blockRule1st=highlight1stBlockRule( text, startIndex); + } + + findBrackets(text,startIndex, -1, blockData); + + setCurrentBlockUserData(blockData); } -void SyntaxHighlighter::highlightBlock(const QString &str) { - //Para aumentar el rendimiento se hace una tabla i_aux con la posición de lo - //que ha encontrado cada expresión regular rules.at(n)->pattern. - //Se aplicará el formato debido a la Rule que tenga la i_aux más pequeña - if(!str.isEmpty() && !rules.isEmpty() && active_ok) { - - int i=0, len=0; //Actual position - int n_min; //Minimal position - - BlockData *dat=(BlockData *)currentBlockUserData(); - if(dat!=NULL) { - dat->bracket.clear(); - } - - for(int n=0;n<__re.size();n++) { - //re[n]=rules.at(n)->pattern; - __i_aux[n] = __re[n].indexIn( str, i); - //printf("%s %d %d\n", rules.at(n)->type.toLocal8Bit().data(), n, __i_aux[n]); - } - - while(i >= 0) { - n_min=-1; - for(int n=0;n<__re.size();n++) - { - if(__i_aux[n]<0) continue; - if(__i_aux[n]type.toLocal8Bit().data(), n, i_aux[n], n_min, i); - if( n_min<0 || __i_aux[n_min]<0 || (__i_aux[n]>=0 && __i_aux[n]<__i_aux[n_min]) ) - { - n_min=n; - if(__i_aux[n]==i) break; - } - } - //printf("n_min=%d elegido\n", n_min); - if(n_min>=0) i=__i_aux[n_min]; - else break; - if( i<0 ) break; - len = __re[n_min].matchedLength(); - - //QStringList list=re[n_min].capturedTexts (); - //printf("\n"); - //for(int n=0;n%s<\n", n, list.at(n).toLocal8Bit().data() ); - //} - //printf("Aplicando %s i=%d len=%d\n", rules.at(n_min)->type.toLocal8Bit().data(), i, len); - if(len<1) break; - //QTextCharFormat i_format=format(i); - //if( !(i_format==strings) ) - - if(rules.at(n_min)->rules.isEmpty()) - { - setFormat(i, len, rules.at(n_min)->format); - - if( rules.at(n_min)->type=="delimiters" ) - { - QString bracket_found=__re[n_min].cap(); - - if(dat==NULL) - { - dat=new BlockData(); - setCurrentBlockUserData(dat); - } - dat->bracket[i]=bracket_found; - - //Do brackets macth - if( braketsMacth_ok && dat != NULL ) - { - if(dat->braket_start_pos>=0) - setFormat(dat->braket_start_pos, 1, _format["bracket match"]); - if(dat->braket_end_pos>=0) - setFormat(dat->braket_end_pos, 1, _format["bracket match"]); - } - } - - } - else - { - //Rules can contains another rules - QString text=str.mid(i,len); - //printf("text=%s\n", text.toLocal8Bit().data() ); - bool format_ok=true; - for(int n=0;nrules.size(); n++) - { - if(rules.at(n_min)->rules.at(n)->pattern.exactMatch(text)) - { - setFormat(i, len, rules.at(n_min)->rules.at(n)->format); - format_ok=false; - break; - } - } - if(format_ok) setFormat(i, len, rules.at(n_min)->format); - } - i+=len; - - } -} +/**Search brackets in one QTextBlock.*/ +static BlockData::Bracket *searchBracket(int i, int increment, int &bracketsCount, BlockData *blockData, BlockData::Bracket *bracket1) +{ + if(blockData==NULL) return NULL; + + if(i==-1) i=blockData->brackets.size()-1; + + for(; i>=0 && ibrackets.size(); i+=increment) + { + BlockData::Bracket *bracket=&(blockData->brackets[i]); + if(bracket->type==bracket1->type) + { + if(bracket->startBracketOk!=bracket1->startBracketOk) + bracketsCount--; + else + bracketsCount++; + + if(bracketsCount==0) + return bracket; + } + } + + //printf("[searchBracket] bracketsCount=%d\n", bracketsCount); + + return NULL; } -int SyntaxHighlighter::forwardSearch(QTextBlock &textBlock, int position, char bracketStart, char bracketEnd) { - int i=position, open=0; - - while(textBlock.isValid()) { - BlockData *dat=(BlockData *)textBlock.userData(); - if(dat!=NULL) { - QList positions=dat->bracket.keys(); - qSort(positions); - for(int k=0;kbracket[b_pos].at(0); - - if(ch==bracketEnd) { - open--; - if(open==0) return b_pos; - } - else if(ch==bracketStart) open++; - } - } - textBlock=textBlock.next(); - i=0; - } - return -1; +void SyntaxHighlighter::setFormatPairBrackets(QPlainTextEdit *textEdit) +{ + QList selections; + + textEdit->setExtraSelections(selections); + + QTextCursor cursor=textEdit->textCursor(); + QTextBlock block=cursor.block(); + BlockData *blockData=(BlockData *)block.userData(); + if(blockData==NULL) return; + + int pos=cursor.position()-block.position(); + + BlockData::Bracket *bracket1; + QTextBlock block_bracket1=block; + + int i=blockData->brackets.size()-1; + + /* + printf("[Syntax::setFormatPairBrackets] brackets.size=%d\n", i+1); + for(int x=0;xbrackets.size();x++) + { + BlockData::Bracket *bracket=&(blockData->brackets[x]); + printf("[Syntax::setFormatPairBrackets] bracket.pos=%d bracket.type=%d bracket.len=%d bracket.start=%d\n", bracket->pos, bracket->type, bracket->length, (bracket->startBracketOk) ); + } + */ + + + for(; i>=0; i--) + { + BlockData::Bracket *bracket=&(blockData->brackets[i]); + if(bracket->pos==pos) + { + bracket1=bracket; + break; + } + } + + if(i<0) return; + + int increment=(bracket1->startBracketOk) ? +1:-1; + int bracketsCount=0; + //i+=increment; + + //Looks in this block the other bracket + BlockData::Bracket *bracket2=NULL; + QTextBlock block_bracket2=block; + + bracket2=searchBracket( i, increment, bracketsCount, blockData, bracket1); + + { //Search brackets in other blocks + while( bracket2==NULL ) + { + if(increment>0) + { + block_bracket2=block_bracket2.next(); + i=0; + } + else + { + block_bracket2=block_bracket2.previous(); + i=-1; + } + + if(!block_bracket2.isValid()) break; + + blockData=(BlockData *)block_bracket2.userData(); + /* + printf("[Syntax::setFormatPairBrackets] Interno brackets.size=%d\n", blockData->brackets.size()); + for(int x=0;xbrackets.size();x++) + { + BlockData::Bracket *bracket=&(blockData->brackets[x]); + printf("[Syntax::setFormatPairBrackets] bracket.pos=%d bracket.type=%d bracket.len=%d bracket.start=%d\n", bracket->pos, bracket->type, bracket->length, (bracket->startBracketOk) ); + } + */ + + bracket2=searchBracket( i, increment, bracketsCount, blockData, bracket1); + } + + if(bracket2==NULL) return; + } + + pos=cursor.position(); + + QTextEdit::ExtraSelection selection1; + + cursor.setPosition(pos+bracket1->length, QTextCursor::KeepAnchor); + selection1.cursor=cursor; + selection1.format=highlightingBracketsRules[bracket1->type].format; + + pos=bracket2->pos+block_bracket2.position(); + QTextEdit::ExtraSelection selection2; + cursor.setPosition(pos); + cursor.setPosition(pos+bracket2->length, QTextCursor::KeepAnchor); + selection2.cursor=cursor; + selection2.format=highlightingBracketsRules[bracket2->type].format; + + selections.append(selection1); selections.append(selection2); + + textEdit->setExtraSelections(selections); + } -int SyntaxHighlighter::backwardSearch(QTextBlock & textBlock, int position, char bracketStart, char bracketEnd) { - int i=position, open=0; - while(textBlock.isValid()) { - BlockData *dat=(BlockData *)textBlock.userData(); - if(dat!=NULL) { - QList positions=dat->bracket.keys(); - qSort(positions); - for(int k=positions.size()-1;k>=0;k--) { - int b_pos=positions[k]; - if(b_pos>i) continue; - QChar ch=dat->bracket[b_pos].at(0); - if(ch==bracketStart) { - open--; - if(open==0) return b_pos; - } - else if(ch==bracketEnd) open++; - } - } - - textBlock=textBlock.previous(); - if(textBlock.isValid() && !textBlock.text().isEmpty()) i=textBlock.length()-1; - } - return -1; +BlockData::BlockData():QTextBlockUserData() +{ } -static void set_block_data(QTextBlock & block0, QTextBlock & block1, int start, int end) { - BlockData *udat=(BlockData *)block0.userData(); - if(udat==NULL) { - udat=new BlockData(); - block0.setUserData(udat); - } - udat->braket_start_pos=start; - if(block0==block1) { - udat->braket_end_pos=end; - } else { - BlockData *udat=(BlockData *)block1.userData(); - if(udat==NULL) { - udat=new BlockData(); - block1.setUserData(udat); - } - udat->braket_end_pos=end; - } -} - -static void clear_block_data(QTextDocument *doc, bool rehigh) { - QTextBlock block=doc->findBlock(0); - while(block.isValid()) { - BlockData *udat=(BlockData *)block.userData(); - if(udat!=NULL && (udat->braket_end_pos!=-1 || udat->braket_start_pos!=-1)) { - udat->braket_end_pos=-1; udat->braket_start_pos=-1; - if(rehigh) { - //QTextCursor cursor(doc); - //cursor.setPosition(block.position()); - //cursor.setBlockFormat(block.blockFormat()); - } - } - block=block.next(); - } -} - -void SyntaxHighlighter::setActive(bool active) { - active_ok=active; -} diff -r 8b09300bbf29 -r e7e671d727b2 gui//src/SyntaxHighlighter.h --- a/gui//src/SyntaxHighlighter.h Thu Apr 14 10:27:09 2011 +0200 +++ b/gui//src/SyntaxHighlighter.h Thu Apr 14 12:24:05 2011 +0200 @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 P.L. Lucas +/* Copyright (C) 2010 P.L. Lucas * * 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 @@ -12,68 +12,96 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. */ -#ifndef SYNTAXHIGHLIGHTER_H -#define SYNTAXHIGHLIGHTER_H -#include -#include -#include -#include -#include -#include "config.h" +#ifndef __SYNTAX_H__ +#define __SYNTAX_H__ -/**SyntaxHighlighter for Octave code.*/ -class SyntaxHighlighter: public QSyntaxHighlighter { - Q_OBJECT -public: - SyntaxHighlighter(QTextDocument *parent); - ~SyntaxHighlighter(); - void highlightBlock(const QString &str); - void load(const QString &file); - - //void setItem(const QString &item, const QString &type); - void setItem(const QString &item, const QString &type, const QString parent=QString() ); - void setComment(const QString &start, const QString &end, const QString &type); - void setType(const QString &type, const QTextCharFormat &format); - - /**Stops syntax highlight*/ - void setActive(bool active); - - static QStringList octave_comands; +#include +#include +#include +#include -public slots: - /**Return true or false if brackets are been macthed*/ - inline bool getIsActiveBraketsMacth() {return braketsMacth_ok;} - - -private: - struct Rule - { - QRegExp pattern; - QString type; - QTextCharFormat format; - QList rules; - }; - - int backwardSearch(QTextBlock &textBlock, int position, char bracketStart, char bracketEnd); - int forwardSearch(QTextBlock &textBlock, int position, char bracketStart, char bracketEnd); - - //static QMap > instances; - - QMap rules_map; - - static QList rules; - QMap _format; - - //Next two properties are used inside highlightBlock method - QVector __i_aux; //Auxiliar positions - QVector __re; //Regular expresions - - bool active_ok; - bool braketsMacth_ok; +class BlockData:public QTextBlockUserData +{ + public: + BlockData(); + + struct Bracket + { + int type; //Type of bracket + int pos; //Position of bracket + int length; //Number of chars of bracket + bool startBracketOk; //Is it a start or end bracket? + }; + + QVector brackets; }; -#endif // SYNTAXHIGHLIGHTER_H +class SyntaxHighlighter:public QSyntaxHighlighter +{ + Q_OBJECT + + struct HighlightingRule + { + QRegExp pattern; + QTextCharFormat format; + int ruleOrder; + int lastFound; + }; + + QVector highlightingRules; + + struct HighlightingBlockRule + { + QRegExp startPattern, endPattern; + QTextCharFormat format; + int ruleOrder; + }; + + QVector highlightingBlockRules; + QVector highlightingBracketsRules; + + struct Rule1st + { + int rule; + int startIndex; + int length; + int ruleOrder; + }; + + /**1st rule to apply from startIndex. + */ + Rule1st highlight1stRule(const QString & text, int startIndex); + + /**1st block rule to apply from startIndex. + */ + Rule1st highlight1stBlockRule(const QString & text, int startIndex); + + /** Set format using rule. + */ + int ruleSetFormat(Rule1st rule); + + /** Set format using block rule. + */ + int blockRuleSetFormat(const QString & text, Rule1st rule1st); + + /** Finds brackets and put them in BlockData. + */ + void findBrackets(const QString & text, int start, int end, BlockData *blockData); + + public: + + SyntaxHighlighter(QObject * parent = 0); + bool load(QString file); + + /**Formats pair of brackets + */ + void setFormatPairBrackets(QPlainTextEdit *textEdit); + + protected: + void highlightBlock ( const QString & text ); +}; +#endif