changeset 13402:17b9b85bd1a6

Added files from QtOctave.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 11 Apr 2011 20:48:10 +0200
parents 8832a2221563
children 276faa3e7423
files gui//Quint.pro gui//src/CodeEdit.cpp gui//src/CodeEdit.h gui//src/MainWindow.cpp gui//src/MainWindow.h gui//src/Syntax.cpp gui//src/Syntax.h
diffstat 7 files changed, 1345 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/gui//Quint.pro	Mon Apr 11 19:06:18 2011 +0200
+++ b/gui//Quint.pro	Mon Apr 11 20:48:10 2011 +0200
@@ -42,7 +42,9 @@
     src/OctaveTerminal.cpp \
     src/VariablesDockWidget.cpp \
     src/HistoryDockWidget.cpp \
-    src/FilesDockWidget.cpp
+    src/FilesDockWidget.cpp \
+    src/CodeEdit.cpp \
+    src/Syntax.cpp
 
 HEADERS += \
         src/TerminalCharacterDecoder.h \
@@ -81,11 +83,13 @@
     src/OctaveTerminal.h \
     src/VariablesDockWidget.h \
     src/HistoryDockWidget.h \
-    src/FilesDockWidget.h
+    src/FilesDockWidget.h \
+    src/CodeEdit.h \
+    src/Syntax.h
 
 INCFLAGS = -g3 $$system(mkoctfile -p INCFLAGS)
 LFLAGS = $$system(mkoctfile -p LFLAGS) \
          $$system(mkoctfile -p OCTAVE_LIBS) \
          $$system(mkoctfile -p LIBS)
-LIBS    += $$LFLAGS -loctave -loctinterp -lreadline -lutil -L../Quint -lqcodeedit
+LIBS    += $$LFLAGS -loctave -loctinterp -lreadline -lutil
 QMAKE_CXXFLAGS  += $$INCFLAGS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//src/CodeEdit.cpp	Mon Apr 11 20:48:10 2011 +0200
@@ -0,0 +1,433 @@
+/* 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 <QContextMenuEvent>
+#include "CodeEdit.h"
+
+CodeEdit::CodeEdit(QWidget *parent, QString syntaxF): QPlainTextEdit(parent)
+, contextMenu(this)
+{
+  syntax=new Syntax(document());
+  if(!syntaxF.isEmpty())
+    syntax->load(syntaxF);
+
+  setUndoRedoEnabled(true);
+  setTabStopWidth(32);
+  setFrameStyle(QFrame::NoFrame);
+
+  autocompletion_ok=true;//(get_config("autoCompletion")!="false");
+  brakets_match_ok=true;//(get_config("bracketsMatch")!="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 &)) );
+  }
+
+  if(brakets_match_ok)
+  {
+  	connect(&braketsTimer, SIGNAL(timeout ()), this, SLOT(braketsMatch()));
+  }
+  braketsTimer.setSingleShot(true);
+  braketsTimer.setInterval(50);
+
+  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()));
+
+   connect(this, SIGNAL( cursorPositionChanged() ), this, SLOT( cursorChanged_cb() ) );
+
+  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()
+{
+	//printf("Borrando la sintaxis\n");
+	delete syntax;
+	//printf("CodeEdit destruido\n");
+}
+
+void CodeEdit::contextMenuEvent(QContextMenuEvent *e)
+{
+  //setTextCursor(cursorForPosition(e->pos()));
+  contextMenu.exec(e->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 * e )
+{
+
+	if(QEvent::KeyPress==e->type() )
+	{
+		QKeyEvent *k=(QKeyEvent *)e;
+		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;i<line.length() && (line.at(i)==' ' || line.at(i)=='\t');i++)
+					start_blank.append(line.at(i));
+				if( automatic_indention_statement_ok )
+				{
+					QRegExp re("^while[ |(].*|^if[ |(].*|^for .*|^switch[ |(].*|^do$|^try|^else|^elseif$");
+					if(re.exactMatch( line.trimmed() ) )
+						start_blank.append("\t");
+				}
+
+				cursor.setPosition(pos);
+				cursor.insertText(start_blank);
+				setTextCursor( cursor );
+			}
+			else
+			{
+				return QPlainTextEdit::event(e);
+			}
+			return true;
+		}
+	}
+	return QPlainTextEdit::event(e);
+}
+
+void CodeEdit::setAutoindent(bool ai_ok)
+{
+	auto_indent=ai_ok;
+}
+
+bool CodeEdit::getAutoindent() {return auto_indent;}
+
+
+void CodeEdit::cursorChanged_cb()
+{
+	if(brakets_match_ok)
+	{
+		if(!context_changed_ok) braketsTimer.start();
+		else
+		{
+			context_changed_ok=false;
+			//braketsTimer.stop();
+		}
+	}
+}
+
+
+void CodeEdit::braketsMatch(bool rehigh)
+{
+	bool text_modified_ok=document()->isModified();
+	text_modified_stop_ok=true;
+	//if(autocompletion_ok) disconnect(this->document(), SIGNAL( contentsChange ( int , int , int  )), this, SLOT(buildAutoCompletionList(int , int , int)) );
+	int pos=textCursor().position();
+	int start=-1, end=-1;
+	if(pos>=0) syntax->braketsMacth(pos, start, end, rehigh);
+	QList<QTextEdit::ExtraSelection> selection_list;
+	if(start>=0 && end >=0)
+	{
+		QTextEdit::ExtraSelection selection;
+		selection.cursor=textCursor();
+		selection.cursor.setPosition(start);
+		selection.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+		selection.format=selection.cursor.blockCharFormat();
+		QBrush brush(Qt::yellow);
+		selection.format.setBackground (brush);
+		selection_list.append(selection);
+		selection.cursor=textCursor();
+		selection.cursor.setPosition(end);
+		selection.cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+		selection_list.append(selection);
+	}
+	setExtraSelections(selection_list);
+	//if(autocompletion_ok) connect(this->document(), SIGNAL( contentsChange ( int , int , int  )), this, SLOT(buildAutoCompletionList(int , int , int)) );
+	document()->setModified(text_modified_ok);
+	text_modified_stop_ok=false;
+}
+
+void CodeEdit::buildAutoCompletionList(int pos, int charsRemoved, int charsAdded )
+{
+	octaveCommandTimer.stop();
+
+	if(brakets_match_ok)
+	{
+		braketsTimer.start();
+		//braketsMatch(true);
+	}
+	document()->setModified(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(0);
+	//Cleans brakets match information
+
+	//while( block.isValid() )
+	//{
+		//block.setUserData(NULL);
+		//block=block.next();
+	//}
+	//Buscando palabra a completar
+	QTextBlock block=document()->findBlock(pos);
+	//int _pos=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(syntax->octave_comands);
+		completion.setCompletionPrefix(word_to_complete);
+		completion.popup()->hide();
+
+		octaveCommandTimer.start();
+
+		return;
+	}
+	else if(word_to_complete.length()<3) {completion.popup()->hide();return;}
+
+	//Searchs help for command
+	//printf("%s\n", word_to_complete.toLocal8Bit().data());
+	emit dynamic_help_required(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();
+}
+
+bool CodeEdit::getbraketsMatchOk()
+{
+	return syntax->getIsActiveBraketsMacth();
+}
+
+void CodeEdit::textModified_cb(bool ok)
+{
+	//printf("[CodeEdit::textModified_cb] Entered\n");
+	if(text_modified_stop_ok) return;
+	emit text_modified(ok);
+	//printf("[CodeEdit::textModified_cb] text_modified emit\n");
+}
+
+void CodeEdit::publicBlockBoundingRectList(QVector<qreal> &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);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//src/CodeEdit.h	Mon Apr 11 20:48:10 2011 +0200
@@ -0,0 +1,111 @@
+/* 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 <QPlainTextEdit>
+#include <QMenu>
+#include <QTextCursor>
+#include "Syntax.h"
+#include <QCompleter>
+#include <QStringListModel>
+#include <QTimer>
+#include "config.h"
+#include <QUndoStack>
+
+
+struct UndoRedoItem
+{
+	int size, pos;
+	QString text;
+};
+
+
+/**TextEdit that supports highlited syntax and autocompletion.*/
+class CodeEdit: public QPlainTextEdit
+{
+  Q_OBJECT
+
+  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;
+
+  //Editor properties
+
+  /**Automatic indention for while, if, for, switch, do and try statements.*/
+  bool automatic_indention_statement_ok;
+  /**Auto completion*/
+  bool autocompletion_ok;
+   /**Brackets Macth*/
+  bool brakets_match_ok;
+
+ protected:
+  Syntax *syntax;
+  QMenu  contextMenu;
+
+  void contextMenuEvent(QContextMenuEvent *e);
+  bool event( QEvent * e );
+
+ public slots:
+  void undo();
+  void redo();
+  void deleteSelection();
+  void toggleBreakpoint();
+  void braketsMatch(bool rehigh=true);
+  void cursorChanged_cb();
+  void buildAutoCompletionList(int pos, int charsRemoved, int charsAdded );
+  void buildAutoCompletionList();
+  void doCompletion(const QModelIndex &index);
+  void octaveCommandCompletion();
+  void textModified_cb(bool ok);
+
+ public:
+  CodeEdit(QWidget *parent = 0, QString syntaxF = QString());
+  ~CodeEdit();
+  void setAutoindent(bool ai_ok);
+  bool getAutoindent();
+
+  bool getbraketsMatchOk();
+ 
+  /**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<qreal>  &list, int &first_line);
+
+ signals:
+  void toggleBreakpoint(int lineno);
+
+  /**Dinamic help required.*/
+  void dynamic_help_required(const QString &text);
+
+  /**Text modified.*/
+  void text_modified(bool ok);
+};
+
+#endif
--- a/gui//src/MainWindow.cpp	Mon Apr 11 19:06:18 2011 +0200
+++ b/gui//src/MainWindow.cpp	Mon Apr 11 20:48:10 2011 +0200
@@ -42,14 +42,14 @@
     m_variablesDockWidget = new VariablesDockWidget(this);
     m_historyDockWidget = new HistoryDockWidget(this);
     m_filesDockWidget = new FilesDockWidget(this);
-    m_codeEdit = new QCodeEdit(this);
+    m_codeEdit = new CodeEdit(this);
     m_centralTabWidget = new QTabWidget(this);
 
     setWindowTitle("Octave");
     setCentralWidget(m_centralTabWidget);
 
     m_centralTabWidget->addTab(m_octaveTerminal, "Terminal");
-    m_centralTabWidget->addTab(m_codeEdit->editor(), "Editor");
+    m_centralTabWidget->addTab(m_codeEdit, "Editor");
 
     addDockWidget(Qt::LeftDockWidgetArea, m_variablesDockWidget);
     addDockWidget(Qt::LeftDockWidgetArea, m_historyDockWidget);
--- a/gui//src/MainWindow.h	Mon Apr 11 19:06:18 2011 +0200
+++ b/gui//src/MainWindow.h	Mon Apr 11 20:48:10 2011 +0200
@@ -27,7 +27,7 @@
 #include "VariablesDockWidget.h"
 #include "HistoryDockWidget.h"
 #include "FilesDockWidget.h"
-#include "qcodeedit.h"
+#include "CodeEdit.h"
 
 // Octave includes
 #undef PACKAGE_BUGREPORT
@@ -92,7 +92,7 @@
     VariablesDockWidget *variablesDockWidget() { return m_variablesDockWidget; }
     HistoryDockWidget *historyDockWidget() { return m_historyDockWidget; }
     FilesDockWidget *filesDockWidget() { return m_filesDockWidget; }
-    QCodeEdit *codeEdit() { return m_codeEdit; }
+    CodeEdit *codeEdit() { return m_codeEdit; }
 
 public slots:
 private:
@@ -102,7 +102,7 @@
     VariablesDockWidget *m_variablesDockWidget;
     HistoryDockWidget *m_historyDockWidget;
     FilesDockWidget *m_filesDockWidget;
-    QCodeEdit *m_codeEdit;
+    CodeEdit *m_codeEdit;
     QTabWidget *m_centralTabWidget;
 
     // Threads for running octave and managing the data interaction.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//src/Syntax.cpp	Mon Apr 11 20:48:10 2011 +0200
@@ -0,0 +1,706 @@
+/* Copyright (C) 2006-2008 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 "Syntax.h"
+#include <iostream>
+#include <QtXml/QXmlSimpleReader>
+#include <QtXml/QXmlDefaultHandler>
+#include <QTextBlockUserData>
+#include <QHash>
+#include <QDir>
+
+//QMap<QString, QVector<Syntax::Rule> > Syntax::instances;
+
+QList<Syntax::Rule*> Syntax::rules;
+QStringList Syntax::octave_comands;
+
+/*** Xml Handler ***/
+class SyntaxXmlHandler:public QXmlDefaultHandler
+{
+private:
+  Syntax *syntax;
+  QString type_name, text;
+  struct Tag
+  {
+  	QString tag, type;
+  	QStringList items;
+  	QList<Tag> childs;
+  };
+  QList<Tag> stack;
+
+  QStringList *octave_comands;
+public:
+  	// Constructor
+  	SyntaxXmlHandler(Syntax *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;
+
+		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;
+	}
+
+
+	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;i<tag.childs.size();i++)
+				{
+					syntax->setItem(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<int,QString> bracket;
+};
+
+
+
+/*** Syntax ***/
+
+Syntax::Syntax(QTextDocument *parent): QSyntaxHighlighter(parent)
+{
+  QTextCharFormat f;
+
+  	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;n<rules.size();n++)
+	{
+		__re.append(rules[n]->pattern);
+		__i_aux.append(-1);
+		//printf("%s %d %d\n", rules.at(n)->type.toLocal8Bit().data(), __re.size(), __i_aux[n]);
+	}
+
+}
+
+
+Syntax::~Syntax()
+{
+	//foreach(Rule *value, rules_map)
+	//{
+	//	delete value;
+	//}
+
+	//This line is added because sometimes Qt try rehighlight text at destroy
+	setDocument(NULL);
+}
+
+void Syntax::load(const QString &path)
+{
+	if(octave_comands.isEmpty())
+	{
+		QString home=QDir::home().path()+"/.qtoctave/commands.txt";
+
+		QFile file(home);
+
+		if (file.open(QFile::ReadOnly))
+		{
+			char buf[1024];
+
+			while(file.readLine(buf, sizeof(buf))>=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;
+	}
+
+
+}
+
+// void Syntax::setItem(const QString &item, const QString &type)
+// {
+//   Rule r;
+//   if(!item.isEmpty())
+//   {
+//     r.pattern = QRegExp(item);
+//     r.type = type;
+//     r.format = _format[type];
+//     rules.push_back(r);
+//   }
+// }
+
+void Syntax::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 Syntax::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 Syntax::setType(const QString &type, const QTextCharFormat &f)
+{
+  _format[type] = f;
+}
+
+void Syntax::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 )
+  {
+
+
+  	//printf("Current block %d\n", currentBlock().blockNumber());
+
+	//setFormat(0, str.length(), _format["variables"]);
+
+  	int i=0, len=0; //Actual position
+	int n_min; //Minimal position
+
+	BlockData *dat=(BlockData *)currentBlockUserData();
+	if(dat!=NULL)
+	{
+		dat->bracket.clear();
+	}
+
+	//int *__i_aux=new int[rules.size()]; //Auxiliar position
+	//QRegExp *__re=new QRegExp[rules.size()];
+
+	//printf("rules %d re %d i_aux %d\n", rules.size(), __re.size(), __i_aux.size());
+
+	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]<i ) __i_aux[n] = __re[n].indexIn( str, i);
+			//printf("%s n=%d i_aux=%d n_min=%d i=%d\n", rules.at(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<list.size();n++)
+		//{
+		//	printf("%d >%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;n<rules.at(n_min)->rules.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;
+		//printf("i=%d\n",i);
+	}
+
+	//delete [] i_aux;
+	//delete [] re;
+
+  }
+}
+
+
+int Syntax::forward_search(QTextBlock & block, int pos, char bracket_start, char bracket_end)
+{
+	int i=pos,  open=0;
+
+	while(block.isValid())
+	{
+		/*
+		if(!block.text().isEmpty())
+		{
+			QString str=block.text();
+			int len=str.length();
+
+			//This line is added to check lower position
+			if(i<0) i=0;
+
+			for(;i<len;i++) //i<len checks upper position
+			{
+				QChar ch=str.at(i);
+
+				if(ch==bracket_end)
+				{
+					open--;
+					if(open==0) return i;
+				}
+				else if(ch==bracket_start) open++;
+			}
+		}*/
+
+		BlockData *dat=(BlockData *)block.userData();
+		if(dat!=NULL)
+		{
+			QList<int> positions=dat->bracket.keys();
+			qSort(positions);
+			for(int k=0;k<positions.size();k++)
+			{
+				int b_pos=positions[k];
+				if(b_pos<i) continue;
+
+				QChar ch=dat->bracket[b_pos].at(0);
+
+				if(ch==bracket_end)
+				{
+					open--;
+					if(open==0) return b_pos;
+				}
+				else if(ch==bracket_start) open++;
+			}
+		}
+
+		block=block.next();
+
+		i=0;
+	}
+
+	return -1;
+}
+
+int Syntax::backward_search(QTextBlock & block, int pos, char bracket_start, char bracket_end)
+{
+	int i=pos,  open=0;
+
+	while(block.isValid())
+	{
+		/*
+		if(!block.text().isEmpty())
+		{
+			QString str=block.text();
+			int len=str.length();
+
+			//This line is added to check upper position
+			if(i>=len) i=len-1;
+
+			for(;i>=0;i--) //i>=0 checks lower position
+			{
+				QChar ch=str.at(i);
+
+				if(ch==bracket_start)
+				{
+					open--;
+					if(open==0) return i;
+				}
+				else if(ch==bracket_end) open++;
+			}
+		}
+		*/
+
+		BlockData *dat=(BlockData *)block.userData();
+		if(dat!=NULL)
+		{
+			QList<int> 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==bracket_start)
+				{
+					open--;
+					if(open==0) return b_pos;
+				}
+				else if(ch==bracket_end) open++;
+			}
+		}
+
+		block=block.previous();
+
+		if(block.isValid() && !block.text().isEmpty()) i=block.length()-1;
+	}
+
+	return -1;
+}
+
+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 Syntax::braketsMacth(int pos, int &start, int &end, bool rehigh)
+{
+	QTextDocument *doc=document();
+
+	if(!rehigh)
+	{
+		clear_block_data(doc, true);
+		return;
+	}
+
+	QTextBlock block0=doc->findBlock(pos), block1;
+	if(!block0.isValid() || block0.text().length()<=0)
+	{
+		return;
+	}
+
+
+	pos=pos-block0.position();
+	if (block0.text().size()<=pos) pos=block0.text().size()-1;
+	if(pos<0) pos=0;
+
+	QChar ch=block0.text().at(pos);
+
+	BlockData *dat=(BlockData *)block0.userData();
+	if(dat!=NULL)
+	{
+		if( !dat->bracket.contains(pos) ) ch=' ';
+	}
+
+
+	block1=block0;
+
+	int i=-1;
+	if(ch=='(')
+	{
+		i=forward_search(block1,pos,'(', ')');
+	}
+	else if(ch==')')
+	{
+		i=backward_search(block1,pos,'(', ')');
+	}
+	else if(ch=='[')
+	{
+		i=forward_search(block1,pos,'[', ']');
+	}
+	else if(ch==']')
+	{
+		i=backward_search(block1,pos,'[', ']');
+	}
+	else if(ch=='{')
+	{
+		i=forward_search(block1,pos,'{', '}');
+	}
+	else if(ch=='}')
+	{
+		i=backward_search(block1,pos,'{', '}');
+	}
+	else
+	{
+		if( braketsMacth_ok )
+		{
+			clear_block_data(doc, rehigh);
+			braketsMacth_ok=false;
+		}
+
+		return;
+	}
+
+	if(i>=0)
+	{
+		clear_block_data(doc, true);
+		//set_block_data(block0, block1, pos, i);
+		start=pos+block0.position();
+		end=i+block1.position();
+		//braketsMacth_ok=true;
+		//if(rehigh) rehighlight();
+		
+		/*
+		QTextCursor cursor(doc);
+
+		cursor.beginEditBlock();
+		cursor.setPosition(block0.position()+pos);
+		cursor.setBlockFormat(block0.blockFormat());
+		if(block1!=block0)
+		{
+			cursor.setPosition(block1.position()+i);
+			cursor.setBlockFormat(block1.blockFormat());
+		}
+		cursor.endEditBlock();
+		*/
+	}
+}
+
+
+void Syntax::setActive(bool active)
+{
+	active_ok=active;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//src/Syntax.h	Mon Apr 11 20:48:10 2011 +0200
@@ -0,0 +1,83 @@
+/* Copyright (C) 2006 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. 
+ */
+
+#ifndef __SYNTAX_H__
+#define __SYNTAX_H__
+#include <QPlainTextEdit>
+#include <QSyntaxHighlighter>
+#include <QVector>
+#include <QTextCharFormat>
+#include <QMap>
+#include "config.h"
+
+/**SyntaxHighlighter for Octave code.*/
+class Syntax: public QSyntaxHighlighter
+{
+ Q_OBJECT
+ public:
+  Syntax(QTextDocument *parent);
+  ~Syntax();
+  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;
+  
+ public slots:
+ 
+ void braketsMacth(int pos, int &start, int &end, bool rehigh=true);
+ 
+ /**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<Rule*> rules;
+  };
+  
+  int backward_search(QTextBlock & block, int pos, char bracket_start, char bracket_end);
+  int forward_search(QTextBlock & block, int pos, char bracket_start, char bracket_end);
+
+  //static QMap<QString, QList<Rule> > instances;
+  
+  QMap<QString, Rule *> rules_map;
+
+  static QList<Rule*> rules;
+  QMap<QString, QTextCharFormat> _format;
+  
+  //Next two properties are used inside highlightBlock method
+  QVector<int> __i_aux; //Auxiliar positions
+  QVector<QRegExp> __re; //Regular expresions
+  
+  bool active_ok;
+  bool braketsMacth_ok;
+};
+
+#endif