/* * Alabastra Project - C++ Editor writed with QT Library V.4 * Copyright (C) Igor Maculan - geocronos@gmail.com Marco Buoncristiano - marco.buoncristiano@gmail.com * 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 "AlTextEdit.h" #include #include #include #include #include #include #include AlTextEdit::AlTextEdit(QWidget *parent) : QTextEdit(parent){ common(); }; AlTextEdit::AlTextEdit():QTextEdit(){ common(); } void AlTextEdit::common(){ defFormat=currentCharFormat(); ar_par[0][0]='('; ar_par[0][1]=')'; ar_par[1][0]='['; ar_par[1][1]=']'; ar_par[2][0]='{'; ar_par[2][1]='}'; doc=new AlDocument(this); setDocument(doc); connect (doc,SIGNAL(fileNameChanged()),this,SLOT(setFileName())); connect (this,SIGNAL(cursorPositionChanged()),this,SLOT(cursorMove())); lit=NULL; setTabStopWidth(10); QStringList word; word << "class" << "public" << "void" << "AlWinMain"; QCompleter *comp=new QCompleter(word,this); setCompleter(comp); connected=false; }; void AlTextEdit::setListWidgetItem(QListWidgetItem *a_lit){ lit=a_lit; }; QListWidgetItem* AlTextEdit::getListWidgetItem(){ return lit; }; AlDocument* AlTextEdit::getAlDocument(){ return doc; }; void AlTextEdit::setFileName(){ emit fileNameChanged(this); }; void AlTextEdit::setCompleter(QCompleter *a_c){ if (a_c!=NULL){ c=a_c; c->setWidget(this); c->setCompletionMode(QCompleter::PopupCompletion); c->setCaseSensitivity(Qt::CaseInsensitive); connect(c,SIGNAL(activated(const QString &)),this,SLOT(insertCompletion(const QString&))); } else return; }; QCompleter* AlTextEdit::getCompleter() const{ return c; }; QString AlTextEdit::textUnderCursor() const{ QTextCursor cur = textCursor(); cur.select(QTextCursor::WordUnderCursor); return cur.selectedText(); }; void AlTextEdit::mousePressEvent(QMouseEvent *e){ lastKeyEvent=NULL; QTextEdit::mousePressEvent(e); }; void AlTextEdit::keyPressEvent(QKeyEvent *e){ lastKeyEvent=e; //Se il menu gi visibile lo chiudo nel caso venga premuto enter esc o tab .... if (c && c->popup()->isVisible()){ switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Escape: case Qt::Key_Tab: case Qt::Key_Backtab: e->ignore(); return; default: break; } } //Controllo che sia stato premuto il tasto rapido CTRL+SPACE bool isShortcutCompletition = ( ( e->modifiers () & Qt::ControlModifier ) && e->key() == Qt::Key_Space); //se non ho un completer oppure non stato premuto il tasto rapido if (!c || !isShortcutCompletition){ //TAB bool normal_key=true; if (e->key()==Qt::Key_Tab && textCursor().hasSelection()){ indent(); normal_key=false; } //BACK TAB if (e->key()==Qt::Key_Backtab && textCursor().hasSelection()){ deindent(); normal_key=false; } if (normal_key){ //Inserimento automatico indentazione in base al numero di tab della riga precedente int ntab=0; if (e->key()==Qt::Key_Return) ntab=textCursor().block().text().count("\t"); //eseguo il comando normale QTextEdit::keyPressEvent(e); //Inserisco i tab nel caso sia una riga nuova ( x l'indentazione ) if (ntab>0){ for (int t=0;t2) completition(e); } } else completition(e); }; /* *Metodo per indentare con il tasto TAB */ void AlTextEdit::indent(){ int i=0; int f=0; int nt=0; i=textCursor().selectionStart(); f=textCursor().selectionEnd(); //creo un nuovo cursore per selezionare da inizio riga QTextCursor csel = textCursor(); QTextCursor ctemp = textCursor(); ctemp.setPosition(i); csel.setPosition(ctemp.block().position()); ctemp.setPosition(f); csel.setPosition(f,QTextCursor::KeepAnchor);//seleziono QTextDocumentFragment frg = csel.selection(); QString s=frg.toPlainText(); int a = s.indexOf(QRegExp("\n.*")); while (a>-1){ s.insert(a+1,'\t'); a=s.indexOf(QRegExp("\n.*"),a+1); nt++; } s.insert(0,'\t'); nt++; csel.insertText(s); QTextCursor c=textCursor(); c.setPosition(i+1); c.setPosition(f+nt,QTextCursor::KeepAnchor);//ripristino la selezione iniziale setTextCursor(c); }; /* *Metodo per DEindentare con il tasto BACKTAB */ void AlTextEdit::deindent(){ int i,f,nt=0; //trovo i valori di selezione i=textCursor().selectionStart(); f=textCursor().selectionEnd(); //creo un nuovo cursore per selezionare da inizio riga QTextCursor csel = textCursor(); QTextCursor ctemp = textCursor(); ctemp.setPosition(i); csel.setPosition(ctemp.block().position()); ctemp.setPosition(f); csel.setPosition(f,QTextCursor::KeepAnchor); //seleziono QTextDocumentFragment frg = csel.selection(); QString s=frg.toPlainText(); //recupero la selezione int a=s.indexOf(QRegExp("\n\t")); //cerco i fineriga seguiti dal tab while (a>-1){ s.remove(a+1,1); a=s.indexOf(QRegExp("\n\t"),a+1); nt++; } if (s.at(0)=='\t'){ s.remove(0,1); nt++; } //sostituisco if (nt>0){ csel.insertText(s); QTextCursor c=textCursor(); c.setPosition(i-1); c.setPosition(f-nt,QTextCursor::KeepAnchor); //ripristino la selezione iniziale setTextCursor(c); } }; bool AlTextEdit::isParentesi(QChar c){ qDebug()<<"carattere" << c; if (c=='(' || c==')' || c=='[' || c==']' ||c=='{' || c=='}' ) return true; else return false; }; /* * Restituisce TRUE se il tasto passatogli come parametro un tasto di modifica * es: lettera invio spazio */ bool AlTextEdit::modifiedKey(int key){ if ( key==Qt::Key_Down || key==Qt::Key_Up || key==Qt::Key_Left || key==Qt::Key_Right || key==Qt::Key_Escape ) return false; else return true; }; void AlTextEdit::cursorMove(){ //Selezione delle parentesi QTextCursor c = textCursor(); QString sel; if ( ! c.hasSelection() ){ //cerco a Sx c = textCursor(); c.movePosition(QTextCursor::Left,QTextCursor::KeepAnchor); if (c.hasSelection() && c.selectedText().size()>0){ sel = c.selectedText(); if ( isParentesi(sel.at(0)) ) selectParentesi(sel.at(0)); else //ripristino il colore originale della vecchia selezione unSelPar(); } }//fine controllo selezione esistente else unSelPar(); }; void AlTextEdit::unSelPar(){ bool m=document()->isModified(); if ( !cur.isNull() ) cur.setCharFormat(defFormat); //ripristino il valore di modifica solo se il tasto premuto non un modificatore if (lastKeyEvent!=NULL){ if ( !modifiedKey(lastKeyEvent->key()) ) document()->setModified(m); } else document()->setModified(m); }; /* *metodo per l'evidenziazione delle parentesi */ void AlTextEdit::selectParentesi(QChar par){ int nopen=0; int nclose=0; int t=0; bool open=false; //cerco la coppia delle parentesi e determino se aperta o chiusa for (int i=0;i<3;i++) { if (ar_par[i][0]==par){ t=i; open=true; } if (ar_par[i][1]==par){ t=i; open=false; } } if (open){ nopen=1; nclose=0; //finche' la somma delle parentesi non si eguaglia QTextCursor csO; QTextCursor csC; QTextCursor cs=textCursor(); cs.movePosition(QTextCursor::Right); while (nopen>nclose){ csO=doc->find(QString("%1").arg(ar_par[t][0]),cs); csC=doc->find(QString("%1").arg(ar_par[t][1]),cs); if (!csO.isNull() && !csC.isNull() && csO.position() < csC.position() ){ nopen++; cs=csO; } if ( !csC.isNull() && (csC.position() < csO.position() || csO.isNull()) ){ nclose++; cs=csC; } if (csC.isNull()) nclose++; cs.movePosition(QTextCursor::Right); } if (!csC.isNull() && nopen>0) { csC.movePosition(QTextCursor::Left); selpar(csC); } }//fine if OPEN else{ //CLOSE nopen=0; nclose=1; //finche' la somma delle parentesi non si eguaglia QTextCursor csO; QTextCursor csC; QTextCursor cs=textCursor(); cs.movePosition(QTextCursor::Left); while (nopenfind(QString("%1").arg(ar_par[t][0]),cs,QTextDocument::FindBackward); csC=doc->find(QString("%1").arg(ar_par[t][1]),cs,QTextDocument::FindBackward); if (!csC.isNull() && !csO.isNull() && csC.position() > csO.position() ){ nclose++; cs=csC; } if ( !csO.isNull() && (csO.position() > csC.position() || csC.isNull()) ){ nopen++; cs=csO; } if (csO.isNull()) nopen++; cs.movePosition(QTextCursor::Left); } if (!csO.isNull() && nclose>0) { csO.movePosition(QTextCursor::Left); selpar(csO); } }//fine if CLOSE }; /* *Evidenzia la partentesi indicata in posizione nc */ void AlTextEdit::selpar(QTextCursor c){ bool mod = document()->isModified(); cur.setCharFormat(defFormat); c.movePosition(QTextCursor::Right,QTextCursor::KeepAnchor); QTextCharFormat format=defFormat; QFont fnt=currentFont(); fnt.setBold(true); format.setFont(fnt); format.setBackground(QBrush(Qt::yellow)); c.setCharFormat(format); cur=c; document()->setModified(mod); }; /* * Apre il menu del completamento automatico */ void AlTextEdit::completition(QKeyEvent *e){ //X chiudere il menu quando non serve const bool CtrlorShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier); if ( !c || ( CtrlorShift && e->text().isEmpty() ) ) return; static QString eow("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); //End of String bool hasModifier = ( e->modifiers() != Qt::NoModifier) && !CtrlorShift; QString completionPrefix = textUnderCursor(); if ( hasModifier || e->text().isEmpty() || eow.contains(e->text().right(1)) ){ c->popup()->hide(); return; } //Completamento!! if (completionPrefix != c->completionPrefix() && !completionPrefix.contains(QRegExp("\t|[ ]"))){ QStringListModel *strModel = new QStringListModel(); QStringList lst; //Popolo la lista di completamento QRegExp exp_compl(completionPrefix+"([a-z]|[A-Z]|[0-9]|[_])*"); QString txt=toPlainText(); int index_compl=txt.indexOf(exp_compl); while (index_compl>-1){ QString add=txt.mid(index_compl,exp_compl.matchedLength()); if (exp_compl.matchedLength()>completionPrefix.length() && !lst.contains(add)) lst<< add; index_compl=txt.indexOf(exp_compl,index_compl+1); } strModel->setStringList(lst); c->setModel((QAbstractItemModel*) strModel); c->setCompletionPrefix(completionPrefix); c->popup()->setCurrentIndex(c->completionModel()->index(0,0)); } QRect cr = cursorRect(); cr.setWidth(c->popup()->sizeHintForColumn(0) + c->popup()->verticalScrollBar()->sizeHint().width()); c->complete(cr); // popup it up! }; void AlTextEdit::insertCompletion(const QString &str){ QTextCursor tc = textCursor(); int extra = str.length() - c->completionPrefix().length(); tc.insertText(str.right(extra)); setTextCursor(tc); }; void AlTextEdit::setConnected(bool c){ connected=c; }; bool AlTextEdit::isConnected(){ return connected; }; void AlTextEdit::comment(){ if (textCursor().hasSelection()){ //trovo i valori di selezione int i=textCursor().selectionStart(); int f=textCursor().selectionEnd(); QTextCursor c=textCursor(); c.setPosition(i); c.insertText("/*"); c.setPosition(f+2); c.insertText("*/"); } };