00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "codeeditor.h"
00023
00024
00025 #include <qkeysequence.h>
00026 #include <qcursor.h>
00027 #include <qcolor.h>
00028 #include <qlabel.h>
00029 #include <qbrush.h>
00030 #include <qlayout.h>
00031 #include <qregexp.h>
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034
00035
00036 #include "../attribute.h"
00037 #include "../classifier.h"
00038 #include "../umldoc.h"
00039 #include "../umlrole.h"
00040
00041 #include "../codeaccessormethod.h"
00042 #include "../codegenerator.h"
00043 #include "../codeclassfield.h"
00044 #include "../codeclassfielddeclarationblock.h"
00045 #include "../codedocument.h"
00046 #include "../codeoperation.h"
00047 #include "../codemethodblock.h"
00048 #include "../classifiercodedocument.h"
00049 #include "../ownedhierarchicalcodeblock.h"
00050 #include "../codegenerators/codegenfactory.h"
00051
00052 #include "codeviewerdialog.h"
00053 #include "classpropdlg.h"
00054 #include "umlattributedialog.h"
00055 #include "umlroledialog.h"
00056 #include "umloperationdialog.h"
00057
00058 CodeEditor::CodeEditor ( const QString & text, const QString & context, CodeViewerDialog * parent, const char * name , CodeDocument * doc)
00059 : QTextEdit ( text, context, parent, name)
00060 {
00061 init(parent, doc);
00062 }
00063
00064 CodeEditor::CodeEditor ( CodeViewerDialog * parent, const char* name, CodeDocument * doc )
00065 : QTextEdit ( parent, name )
00066 {
00067 init(parent, doc);
00068 }
00069
00070
00071
00072
00073 CodeEditor::~CodeEditor() { }
00074
00075
00076 void CodeEditor::clearText () {
00077
00078
00079 m_selectedTextBlock = 0;
00080 m_textBlockList.clear();
00081 m_tbInfoMap->clear();
00082
00083
00084 clear();
00085
00086 }
00087
00088 Settings::CodeViewerState CodeEditor::getState()
00089 {
00090 return m_parentDlg->getState();
00091 }
00092
00093 QLabel * CodeEditor::getComponentLabel() {
00094 return m_parentDlg->componentLabel;
00095 }
00096
00097
00098
00099 void CodeEditor::clicked(int para, int pos)
00100 {
00101 getComponentLabel()->setText("para:"+QString::number(para)+" pos:"+QString::number(pos));
00102 }
00103
00104
00105 bool CodeEditor::close ( bool alsoDelete )
00106 {
00107
00108
00109 if(m_lastTextBlockToBeEdited)
00110 {
00111 updateTextBlockFromText (m_lastTextBlockToBeEdited);
00112 m_lastTextBlockToBeEdited = 0;
00113 }
00114
00115 return QTextEdit::close(alsoDelete);
00116
00117 }
00118
00119 void CodeEditor::doubleClicked(int para, int pos)
00120 {
00121
00122 m_lastPara = para;
00123 m_lastPos = pos;
00124
00125
00126
00127 TextBlock * tBlock = m_textBlockList.at(para);
00128 editTextBlock(tBlock, para);
00129
00130 }
00131
00132
00133
00134 void CodeEditor::editTextBlock(TextBlock * tBlock, int para) {
00135
00136 if(tBlock)
00137 {
00138 TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
00139 if(info) {
00140 UMLObject *obj = info->getParent();
00141 if(obj)
00142 {
00143
00144 UMLAttribute * at = 0;
00145 UMLRole * role = 0;
00146 UMLOperation * op = 0;
00147
00148 if( (at = dynamic_cast<UMLAttribute*>(obj)) )
00149 {
00150 UMLAttributeDialog dlg( this, at);
00151 if( dlg.exec() ) { rebuildView(para); }
00152 }
00153 else if( (dynamic_cast<UMLClassifier*>(obj)) )
00154 {
00155 if (obj->showProperties())
00156 rebuildView(para);
00157 }
00158 else if( (role = dynamic_cast<UMLRole*>(obj)))
00159 {
00160 UMLRoleDialog dlg(this,role);
00161 if( dlg.exec() ) { rebuildView(para); }
00162 }
00163 else if( (op = dynamic_cast<UMLOperation*>(obj)) )
00164
00165 {
00166 UMLOperationDialog dlg(this,op);
00167 if( dlg.exec() ) { rebuildView(para); }
00168 }
00169 else
00170 {
00171 kError()<<" CodeViewerDlg ERROR: UNKNOWN parent for textBlock"<<endl;
00172 }
00173
00174 }
00175 }
00176 }
00177 }
00178
00179
00180 bool CodeEditor::StringIsBlank(const QString &str)
00181 {
00182 if(str.isEmpty() || str.stripWhiteSpace().isEmpty())
00183 return true;
00184 return false;
00185 }
00186
00187 void CodeEditor::keyPressEvent ( QKeyEvent * e ) {
00188
00189
00190
00191 if((e->ascii() == 8) )
00192 m_backspacePressed = true;
00193
00194
00195 if((e->ascii() == 10) || (e->ascii() == 13) || (e->text() == "\r\n"))
00196 m_newLinePressed = true;
00197
00198 QTextEdit::keyPressEvent(e);
00199 }
00200
00201 void CodeEditor::loadFromDocument ()
00202 {
00203
00204
00205 clearText();
00206
00207
00208 QString caption = m_parentDoc->getFileName() + m_parentDoc->getFileExtension();
00209 setCaption( tr2i18n( caption.latin1() ) );
00210
00211
00212 QString header = m_parentDoc->getHeader()->toString();
00213 QString componentName = QString("header for file ") +caption;
00214 if(!StringIsBlank(header))
00215 insert(header,m_parentDoc->getHeader(),false,getState().fontColor,
00216 getState().nonEditBlockColor,0,componentName);
00217
00218
00219 TextBlockList * items = m_parentDoc->getTextBlockList();
00220 appendText(items);
00221
00222 setCursorPosition(0,0);
00223
00224 }
00225
00226 void CodeEditor::insert (const QString & text, TextBlock * parent, bool editable, const QColor & fgcolor, const QColor & bgcolor, UMLObject * umlobj, const QString & displayName, int startLine)
00227 {
00228
00229
00230 bool isInsert = false;
00231 setColor(fgcolor);
00232
00233
00234
00235 if(startLine == -1)
00236 {
00237 startLine = paragraphs()-1;
00238 QTextEdit::append(text);
00239 }
00240 else
00241 {
00242 isInsert = true;
00243 QTextEdit::insertAt(text, startLine, 0);
00244 }
00245
00246
00247
00248
00249
00250 int endLine = text.contains(QRegExp("\n")) + startLine -1;
00251 if(m_isHighlighted)
00252 for(int para=startLine;para<=endLine;para++)
00253 setParagraphBackgroundColor(para,bgcolor);
00254
00255
00256
00257 TextBlockInfo * tbinfo;
00258 if(m_tbInfoMap->contains(parent))
00259 tbinfo = (*m_tbInfoMap)[parent];
00260 else {
00261 tbinfo = new TextBlockInfo();
00262 tbinfo->displayName = displayName;
00263 tbinfo->isCodeAccessorMethod = dynamic_cast<CodeAccessorMethod*>(parent) ? true : false;
00264 m_tbInfoMap->insert(parent,tbinfo);
00265 }
00266
00267
00268 if(umlobj && !tbinfo->getParent())
00269 {
00270 tbinfo->displayName = displayName;
00271 tbinfo->setParent(umlobj);
00272 tbinfo->isClickable = textBlockIsClickable(umlobj);
00273 }
00274
00275
00276 for(int para=startLine;para<=endLine;para++)
00277 m_textBlockList.insert(para,parent);
00278
00279
00280
00281 int start = startLine - m_textBlockList.findRef(parent);
00282 int size = endLine-startLine;
00283
00284
00285 ParaInfo * item = new ParaInfo();
00286 item->start = start;
00287 item->size= size;
00288 item->fgcolor = fgcolor;
00289 item->bgcolor = bgcolor;
00290 item->isEditable = editable;
00291
00292 if(isInsert)
00293 {
00294
00295
00296
00297
00298
00299 int increase = size + 1;
00300 QMap<TextBlock*,TextBlockInfo*>::Iterator it;
00301 for ( it = m_tbInfoMap->begin(); it != m_tbInfoMap->end(); ++it )
00302 {
00303 TextBlock * tblock = it.key();
00304 TextBlockInfo * thisTbInfo = it.data();
00305 int firstLoc = m_textBlockList.findRef(tblock);
00306 ParaInfo * lastPi = thisTbInfo->m_paraList.last();
00307
00308 for(ParaInfo * pi = thisTbInfo->m_paraList.first(); pi; pi = thisTbInfo->m_paraList.next())
00309 {
00310 int minPara = pi->start+firstLoc;
00311
00312
00313
00314 if(!pi->start && (startLine > (lastPi->start+firstLoc+lastPi->size) || endLine < minPara) )
00315 break;
00316
00317
00318
00319 if(pi->start && minPara >= endLine )
00320 pi->start += increase;
00321
00322 }
00323 }
00324
00325 }
00326
00327 tbinfo->m_paraList.append(item);
00328
00329 }
00330
00331 void CodeEditor::appendText(TextBlockList * items)
00332 {
00333
00334 for (TextBlock *tb = items->first(); tb; tb = items->next())
00335 {
00336
00337
00338
00339
00340
00341 HierarchicalCodeBlock * hb = dynamic_cast<HierarchicalCodeBlock *>(tb);
00342 CodeMethodBlock * mb = 0;
00343 CodeClassFieldDeclarationBlock * db = 0;
00344 CodeBlockWithComments * cb = 0;
00345
00346 if(hb)
00347 appendText(hb);
00348 else if ( (mb = dynamic_cast<CodeMethodBlock*>(tb)) )
00349 appendText(mb);
00350 else if ( (db = dynamic_cast<CodeClassFieldDeclarationBlock*>(tb)) )
00351 appendText(db);
00352 else if ( (cb = dynamic_cast<CodeBlockWithComments*>(tb)) )
00353 appendText(cb);
00354
00355
00356
00357
00358
00359
00360 else
00361 appendText(tb);
00362 }
00363
00364 }
00365
00366 void CodeEditor::appendText (CodeComment * comment, TextBlock * parent, UMLObject * umlObj , const QString & componentName)
00367 {
00368
00369 if(!comment->getWriteOutText() && !m_showHiddenBlocks)
00370 return;
00371
00372 QColor bgcolor = getState().nonEditBlockColor;
00373 if(!comment->getWriteOutText() && m_showHiddenBlocks)
00374 bgcolor = getState().hiddenColor;
00375
00376 QString indent = comment->getIndentationString();
00377 QString text = comment->toString();
00378 if(!StringIsBlank(text))
00379 insert(text,parent,true,getState().fontColor, bgcolor, umlObj, componentName);
00380
00381 }
00382
00383 void CodeEditor::appendText (CodeBlockWithComments * cb ) {
00384
00385 if(!cb->getWriteOutText() && !m_showHiddenBlocks)
00386 return;
00387
00388 QString indent = cb->getIndentationString();
00389 QString body = cb->formatMultiLineText (cb->getText(), indent, "\n");
00390
00391 QColor bgcolor = getState().editBlockColor;
00392 QString componentName = QString("CodeBlock");
00393
00394 appendText(cb->getComment(), cb, 0, componentName);
00395
00396 if(!cb->getWriteOutText() && m_showHiddenBlocks)
00397 bgcolor = getState().hiddenColor;
00398
00399 if(!StringIsBlank(body))
00400 insert(body,cb,true,getState().fontColor,bgcolor,0);
00401
00402 }
00403
00404 void CodeEditor::appendText (CodeClassFieldDeclarationBlock * db ) {
00405
00406 if(!db->getWriteOutText() && !m_showHiddenBlocks)
00407 return;
00408
00409 QString indent = db->getIndentationString();
00410 QString body = db->formatMultiLineText (db->getText(), indent, "\n");
00411
00412 UMLObject * parentObj = db->getParentClassField()->getParentObject();
00413
00414 QColor bgcolor = getState().editBlockColor;
00415 QString componentName = QString("");
00416 if(parentObj)
00417 {
00418 if(db->getParentClassField()->parentIsAttribute()) {
00419 componentName = parentDocName + "::attribute_field(" + parentObj->getName() + ')';
00420 } else {
00421 UMLRole * role = dynamic_cast<UMLRole*>(parentObj);
00422 componentName = parentDocName + "::association_field(" + role->getName() + ')';
00423 }
00424 bgcolor = getState().umlObjectColor;
00425 }
00426
00427 appendText(db->getComment(), db, parentObj,componentName);
00428
00429 if(!db->getWriteOutText() && m_showHiddenBlocks)
00430 bgcolor = getState().hiddenColor;
00431
00432 if(!StringIsBlank(body))
00433 insert(body,db,false,getState().fontColor,bgcolor,parentObj);
00434
00435
00436 }
00437
00438 void CodeEditor::appendText (CodeMethodBlock * mb) {
00439
00440
00441
00442
00443 if(!mb->getWriteOutText() && (!m_showHiddenBlocks || dynamic_cast<CodeAccessorMethod*>(mb)))
00444 return;
00445
00446 QColor bgcolor = getState().umlObjectColor;
00447 QString indent = mb->getIndentationString();
00448 QString bodyIndent = mb->getIndentationString(mb->getIndentationLevel()+1);
00449
00450 QString startText = mb->formatMultiLineText ( mb->getStartMethodText(), indent, "\n");
00451 QString body = mb->formatMultiLineText (mb->getText(), bodyIndent, "\n");
00452 QString endText = mb->formatMultiLineText( mb->getEndMethodText(), indent, "\n");
00453
00454 if(body.isEmpty())
00455 body = " \n";
00456
00457 if(!mb->getWriteOutText() && m_showHiddenBlocks)
00458 {
00459
00460 bgcolor = getState().hiddenColor;
00461 }
00462
00463 QString componentName = QString("<b>parentless method\?</b>");
00464
00465
00466 CodeOperation * op = dynamic_cast<CodeOperation*>(mb);
00467 CodeAccessorMethod * accessor = dynamic_cast<CodeAccessorMethod*>(mb);
00468 UMLObject * parentObj = 0;
00469 if(op)
00470 {
00471 parentObj = op->getParentOperation();
00472 if(((UMLOperation*)parentObj)->isConstructorOperation())
00473 componentName = parentDocName + "::operation("+ parentObj->getName()+") constructor method";
00474 else
00475 componentName = parentDocName + "::operation("+ parentObj->getName()+") method";
00476 }
00477 if(accessor)
00478 {
00479 parentObj = accessor->getParentObject();
00480 if(accessor->getParentClassField()->parentIsAttribute()) {
00481 componentName = parentDocName + "::attribute_field(" + parentObj->getName() + ") accessor method";
00482 } else {
00483 UMLRole * role = dynamic_cast<UMLRole*>(parentObj);
00484 componentName = parentDocName + "::association_field(" + role->getName() + ") accessor method";
00485 }
00486
00487 }
00488
00489
00490 appendText(mb->getComment(), mb->getComment(), parentObj, componentName);
00491
00492 if(!StringIsBlank(startText))
00493 insert(startText,mb,false,getState().fontColor,bgcolor,parentObj);
00494
00495
00496 insert(body,mb,true,getState().fontColor,bgcolor,parentObj);
00497 if(!StringIsBlank(endText))
00498 insert(endText,mb,false,getState().fontColor,bgcolor,parentObj);
00499
00500 }
00501
00502 void CodeEditor::appendText (TextBlock * tb) {
00503
00504 if(!tb->getWriteOutText() && !m_showHiddenBlocks)
00505 return;
00506
00507 QColor bgcolor = getState().nonEditBlockColor;
00508 if(!tb->getWriteOutText() && m_showHiddenBlocks)
00509 bgcolor = getState().hiddenColor;
00510
00511 QString str = tb->toString();
00512 insert(str,tb,false,getState().fontColor,bgcolor);
00513
00514 }
00515
00516 void CodeEditor::appendText(HierarchicalCodeBlock * hblock)
00517 {
00518
00519 if(!hblock->getWriteOutText() && !m_showHiddenBlocks)
00520 return;
00521
00522 OwnedHierarchicalCodeBlock * test = dynamic_cast<OwnedHierarchicalCodeBlock *>(hblock);
00523 UMLObject * parentObj = 0;
00524 QString componentName = QString("");
00525 QColor paperColor = getState().nonEditBlockColor;
00526 if(test)
00527 {
00528 parentObj = test->getParentObject();
00529 UMLClassifier *c = dynamic_cast<UMLClassifier*>(parentObj);
00530 if (c) {
00531 QString typeStr;
00532 if (c->isInterface())
00533 typeStr = "Interface";
00534 else
00535 typeStr = "Class";
00536 componentName = parentDocName + "::" + typeStr + '(' + parentObj->getName() + ')';
00537 } else {
00538 componentName = parentDocName + "::UNKNOWN(" + parentObj->getName() + ')';
00539 }
00540
00541 paperColor = getState().umlObjectColor;
00542 }
00543
00544 if(!hblock->getWriteOutText() && m_showHiddenBlocks)
00545 paperColor = getState().hiddenColor;
00546
00547 TextBlockList * items = hblock->getTextBlockList();
00548 QString indent = hblock->getIndentationString();
00549 QString startText = hblock->formatMultiLineText ( hblock->getStartText(), indent, "\n");
00550 QString endText = hblock->formatMultiLineText( hblock->getEndText(), indent, "\n");
00551
00552 appendText(hblock->getComment(), hblock, parentObj, componentName);
00553
00554 if(!StringIsBlank(startText))
00555 insert(startText,hblock,false,getState().fontColor,paperColor, parentObj);
00556 appendText(items);
00557 if(!StringIsBlank(endText))
00558 insert(endText,hblock,false,getState().fontColor,paperColor);
00559
00560 }
00561
00562 void CodeEditor::insertParagraph ( const QString & text, int para )
00563 {
00564 QTextEdit::insertParagraph(text,para);
00565 }
00566
00567 void CodeEditor::removeParagraph ( int para )
00568 {
00569 QTextEdit::removeParagraph(para);
00570 }
00571
00572
00573
00574 bool CodeEditor::textBlockIsClickable(UMLObject * obj)
00575 {
00576
00577 if( dynamic_cast<UMLAttribute*>(obj) )
00578 return true;
00579 else if( dynamic_cast<UMLClassifier*>(obj) )
00580 return true;
00581 else if( dynamic_cast<UMLRole*>(obj) )
00582 return true;
00583 else if( dynamic_cast<UMLOperation*>(obj) )
00584 return true;
00585
00586 return false;
00587 }
00588
00589 void CodeEditor::slotChangeSelectedBlockView()
00590 {
00591 TextBlock * tb = m_selectedTextBlock;
00592 if(tb) {
00593 tb->setWriteOutText(tb->getWriteOutText() ? false : true );
00594 rebuildView(m_lastPara);
00595 }
00596
00597 }
00598
00599
00600
00601 void CodeEditor::slotChangeSelectedBlockCommentView()
00602 {
00603
00604 TextBlock * tb = m_selectedTextBlock;
00605 CodeBlockWithComments * cb = 0;
00606 if(tb && (cb = dynamic_cast<CodeBlockWithComments*>(tb)))
00607 {
00608 cb->getComment()->setWriteOutText(cb->getComment()->getWriteOutText() ? false : true );
00609 rebuildView( m_lastPara );
00610 }
00611
00612 }
00613
00614 void CodeEditor::slotInsertCodeBlockBeforeSelected()
00615 {
00616
00617 TextBlock * tb = m_selectedTextBlock;
00618 CodeBlockWithComments * newBlock = m_parentDoc->newCodeBlockWithComments();
00619 newBlock->setText("<<INSERT>>");
00620 newBlock->getComment()->setWriteOutText(false);
00621
00622 m_parentDoc->insertTextBlock(newBlock, tb, false);
00623
00624 int location = m_textBlockList.findRef(m_selectedTextBlock);
00625
00626 QString body = newBlock->formatMultiLineText (newBlock->getText(), newBlock->getIndentationString(), "\n");
00627
00628 insert(body,newBlock,true,getState().fontColor,
00629 getState().editBlockColor,0,QString("CodeBlock"),location);
00630
00631 }
00632
00633 void CodeEditor::slotInsertCodeBlockAfterSelected()
00634 {
00635
00636 TextBlock * tb = m_selectedTextBlock;
00637 CodeBlockWithComments * newBlock = m_parentDoc->newCodeBlockWithComments();
00638 newBlock->setText("<<INSERT>>");
00639 newBlock->getComment()->setWriteOutText(false);
00640
00641 m_parentDoc->insertTextBlock(newBlock, tb, true);
00642
00643
00644 TextBlockInfo *tbinfo = (*m_tbInfoMap)[m_selectedTextBlock];
00645 ParaInfo * lastpi = tbinfo->m_paraList.last();
00646 int location = m_textBlockList.findRef(m_selectedTextBlock) + lastpi->start + lastpi->size + 1;
00647
00648 QString body = newBlock->formatMultiLineText (newBlock->getText(), newBlock->getIndentationString(), "\n");
00649
00650 insert(body,newBlock,true,getState().fontColor,
00651 getState().editBlockColor,0,QString("CodeBlock"),location);
00652
00653 }
00654
00655 QPopupMenu * CodeEditor::createPopupMenu ( const QPoint & pos )
00656 {
00657
00658 TextBlock * tb = m_selectedTextBlock;
00659 m_lastPara = paragraphAt(pos);
00660
00661 QPopupMenu * menu = new QPopupMenu(this);
00662
00663
00664
00665
00666 menu->blockSignals(true);
00667
00668 if (m_selectedTextBlock)
00669 {
00670 if(tb->getWriteOutText())
00671 menu->insertItem("Hide",this,SLOT(slotChangeSelectedBlockView()), Key_H, 0);
00672 else
00673 menu->insertItem("Show",this,SLOT(slotChangeSelectedBlockView()), Key_S, 0);
00674
00675 CodeBlockWithComments * cb = dynamic_cast<CodeBlockWithComments*>(tb);
00676 if(cb)
00677 if(cb->getComment()->getWriteOutText())
00678 menu->insertItem("Hide Comment",this,SLOT(slotChangeSelectedBlockCommentView()), CTRL+Key_H, 1);
00679 else
00680 menu->insertItem("Show Comment",this,SLOT(slotChangeSelectedBlockCommentView()), CTRL+Key_S, 1);
00681 menu->insertSeparator();
00682
00683 menu->insertItem("Insert Code Block Before",this,SLOT(slotInsertCodeBlockBeforeSelected()), CTRL+Key_B, 2);
00684 menu->insertItem("Insert Code Block After",this,SLOT(slotInsertCodeBlockAfterSelected()), CTRL+Key_A, 3);
00685
00686 menu->insertSeparator();
00687
00688 menu->insertItem("Copy",this,SLOT(slotCopyTextBlock()), CTRL+Key_C, 4);
00689 menu->insertItem("Paste",this,SLOT(slotPasteTextBlock()), CTRL+Key_V, 5);
00690 menu->insertItem("Cut",this,SLOT(slotCutTextBlock()), CTRL+Key_X, 6);
00691
00692
00693 if(m_selectedTextBlock == m_parentDoc->getHeader())
00694 menu->setItemEnabled (2, false);
00695
00696 if(!m_textBlockToPaste)
00697 menu->setItemEnabled (5, false);
00698
00699 if(!tb->canDelete())
00700 menu->setItemEnabled (6, false);
00701
00702
00703
00704 if(dynamic_cast<OwnedCodeBlock*>(m_selectedTextBlock) ||
00705 dynamic_cast<HierarchicalCodeBlock*>(m_selectedTextBlock))
00706 menu->setItemEnabled (4, false);
00707
00708
00709
00710 }
00711
00712 return menu;
00713 }
00714
00715 void CodeEditor::slotCopyTextBlock ( )
00716 {
00717
00718 if(dynamic_cast<HierarchicalCodeBlock*>(m_selectedTextBlock))
00719 m_textBlockToPaste = m_parentDoc->newHierarchicalCodeBlock();
00720 else if(dynamic_cast<CodeBlockWithComments*>(m_selectedTextBlock))
00721 m_textBlockToPaste = m_parentDoc->newCodeBlockWithComments();
00722 else if(dynamic_cast<CodeBlock*>(m_selectedTextBlock))
00723 m_textBlockToPaste = m_parentDoc->newCodeBlock();
00724 else if(dynamic_cast<CodeComment*>(m_selectedTextBlock))
00725 m_textBlockToPaste = CodeGenFactory::newCodeComment(m_parentDoc);
00726 else
00727 {
00728 kError()<<" ERROR: CodeEditor can't copy selected block:"<<m_selectedTextBlock<<" of unknown type"<<endl;
00729 m_textBlockToPaste = 0;
00730 return;
00731 }
00732
00733 m_textBlockToPaste->setAttributesFromObject(m_selectedTextBlock);
00734
00735 }
00736
00737 void CodeEditor::slotCutTextBlock ( ) {
00738
00739
00740 slotCopyTextBlock();
00741
00742
00743
00744 if(m_selectedTextBlock->canDelete())
00745 {
00746
00747
00748 if (m_lastTextBlockToBeEdited && m_lastTextBlockToBeEdited == (CodeBlock*) m_selectedTextBlock)
00749 {
00750 updateTextBlockFromText (m_lastTextBlockToBeEdited);
00751 m_lastTextBlockToBeEdited = 0;
00752 }
00753
00754 m_parentDoc->removeTextBlock(m_selectedTextBlock);
00755 rebuildView(m_lastPara);
00756
00757 m_selectedTextBlock = 0;
00758 }
00759
00760 }
00761
00762 void CodeEditor::slotPasteTextBlock ( ) {
00763
00764 if(m_textBlockToPaste)
00765 {
00766 m_parentDoc->insertTextBlock(m_textBlockToPaste, m_selectedTextBlock);
00767 m_textBlockToPaste = 0;
00768 rebuildView(m_lastPara);
00769 }
00770
00771 }
00772
00773 void CodeEditor::slotRedrawText() {
00774 rebuildView(m_lastPara);
00775 }
00776
00777 void CodeEditor::init ( CodeViewerDialog * parentDlg, CodeDocument * parentDoc ) {
00778
00779
00780 parentDoc->synchronize();
00781
00782 m_parentDlg = parentDlg;
00783 m_parentDoc = parentDoc;
00784
00785 setUndoRedoEnabled( false );
00786 setCursor( QCursor( 0 ) );
00787 setMouseTracking( true );
00788 setReadOnly (true);
00789 m_isHighlighted = getState().blocksAreHighlighted;
00790 m_showHiddenBlocks = getState().showHiddenBlocks;
00791
00792 m_newLinePressed = false;
00793 m_backspacePressed = false;
00794 m_textBlockToPaste = 0;
00795 m_selectedTextBlock = 0;
00796 m_lastTextBlockToBeEdited = 0;
00797 m_tbInfoMap = new QMap<TextBlock *, TextBlockInfo*>;
00798
00799 setFont( getState().font );
00800
00801
00802 ClassifierCodeDocument * cdoc = dynamic_cast<ClassifierCodeDocument*>(m_parentDoc);
00803 if(cdoc)
00804 parentDocName = cdoc->getParentClassifier()->getName();
00805 else
00806 parentDocName = "";
00807
00808
00809
00810
00811 QBrush pbrush = QBrush ( getState().paperColor);
00812 setPaper(pbrush);
00813
00814
00815
00816
00817
00818 connect(this,SIGNAL(doubleClicked(int,int)),this,SLOT(doubleClicked(int,int)));
00819 connect(this,SIGNAL(cursorPositionChanged(int,int)),this,SLOT(cursorPositionChanged(int,int)));
00820
00821
00822 loadFromDocument();
00823
00824 }
00825
00826 void CodeEditor::updateTextBlockFromText (TextBlock * block) {
00827
00828 if (block) {
00829
00830 CodeMethodBlock * cmb = dynamic_cast<CodeMethodBlock*>(block);
00831
00832 QString baseIndent = block->getIndentationString(block->getIndentationLevel()+(cmb ? 1 : 0));
00833
00834 TextBlockInfo *info = (*m_tbInfoMap)[block];
00835 UMLObject * parentObj = info->getParent();
00836 int pstart = m_textBlockList.findRef(block);
00837 QString content = "";
00838
00839
00840 QPtrList<ParaInfo> list = info->m_paraList;
00841 for(ParaInfo * item = list.first(); item; item=list.next())
00842 {
00843 if(item->isEditable)
00844 {
00845 int lastpara = item->start+pstart+item->size;
00846 int endEdit = block->lastEditableLine();
00847 int lastLineToAddNewLine = lastpara + endEdit;
00848 for(int para=(item->start+pstart);para<=lastpara;para++)
00849 {
00850 QString line = block->unformatText(text(para), baseIndent);
00851 content += line;
00852
00853
00854 if(!line.isEmpty() && para != lastLineToAddNewLine)
00855 content += "\n";
00856 }
00857 }
00858 }
00859
00860
00861 block->setText(content);
00862
00863
00864
00865 if(parentObj && !info->isCodeAccessorMethod)
00866 parentObj->setDoc(content);
00867
00868
00869 if(cmb)
00870 cmb->setContentType(CodeBlock::UserGenerated);
00871
00872 }
00873 }
00874
00875 void CodeEditor::cursorPositionChanged(int para, int pos)
00876 {
00877
00878
00879 if(pos < 0)
00880 return;
00881
00882
00883 bool lastParaIsEditable = isParaEditable(m_lastPara);
00884
00885
00886
00887 if(lastParaIsEditable)
00888 {
00889
00890
00891 if((para-1) == m_lastPara && m_newLinePressed )
00892 expandSelectedParagraph ( m_lastPara );
00893
00894
00895
00896 if((para+1) == m_lastPara && m_backspacePressed )
00897 contractSelectedParagraph( para );
00898
00899 }
00900
00901
00902
00903 bool editPara = isParaEditable(para);
00904 if(editPara) {
00905
00906 TextBlock * tBlock = m_textBlockList.at(para);
00907 CodeMethodBlock * cmb = dynamic_cast<CodeMethodBlock*>(tBlock);
00908
00909
00910 QString currentParaText = text(para);
00911 QString baseIndent = tBlock->getNewEditorLine(tBlock->getIndentationLevel()+(cmb ? 1 : 0));
00912
00913 int minPos = baseIndent.length();
00914
00915
00916 if(!m_backspacePressed && !currentParaText.contains(QRegExp('^'+baseIndent)))
00917 {
00918 insertAt(baseIndent,para,0);
00919 setCursorPosition(para,pos+minPos);
00920 return;
00921 }
00922
00923 if(pos<minPos)
00924 {
00925
00926 bool priorParaIsEditable = isParaEditable(para-1);
00927 if(m_backspacePressed && para && priorParaIsEditable)
00928 {
00929 int endOfPriorLine = paragraphLength(para-1);
00930
00931
00932 QString contents = text(para);
00933 contents = contents.right(contents.length()-m_lastPos+1);
00934
00935
00936
00937
00938 if(paraIsNotSingleLine(para))
00939 {
00940 removeParagraph(para);
00941 insertAt(contents,(para-1),endOfPriorLine);
00942 setCursorPosition((para-1),endOfPriorLine);
00943 }
00944
00945 } else {
00946
00947
00948
00949
00950 if(m_backspacePressed && !priorParaIsEditable)
00951 {
00952 QString contents = text(para);
00953 contents = contents.right(contents.length()-m_lastPos+1);
00954 contents = baseIndent + contents.left(contents.length()-1);
00955 insertParagraph(contents,para+1);
00956 removeParagraph(para);
00957
00958
00959
00960 if(cmb && contents.contains(QRegExp('^'+baseIndent+"\\s$")))
00961 {
00962 cmb->setContentType(CodeBlock::AutoGenerated);
00963 cmb->syncToParent();
00964 }
00965
00966 }
00967
00968
00969 setCursorPosition(para,minPos);
00970
00971 }
00972 return;
00973 }
00974 }
00975
00976
00977
00978 if((editPara && !m_lastTextBlockToBeEdited) || (!editPara && m_lastTextBlockToBeEdited)) {
00979
00980 setReadOnly(editPara ? false : true);
00981
00982
00983
00984 if(m_lastTextBlockToBeEdited && (m_lastTextBlockToBeEdited != m_textBlockList.at(para) || !editPara))
00985 {
00986 updateTextBlockFromText (m_lastTextBlockToBeEdited);
00987 m_lastTextBlockToBeEdited = 0;
00988 }
00989
00990 if(editPara)
00991 m_lastTextBlockToBeEdited = m_textBlockList.at(para);
00992 else
00993 m_lastTextBlockToBeEdited = 0;
00994
00995 }
00996
00997 m_lastPara = para;
00998 m_lastPos = pos;
00999 m_newLinePressed = false;
01000 m_backspacePressed = false;
01001
01002 }
01003
01004 bool CodeEditor::paraIsNotSingleLine (int para)
01005 {
01006 TextBlock * tBlock = m_textBlockList.at(para);
01007 if(tBlock)
01008 {
01009 int pstart = m_textBlockList.findRef(tBlock);
01010 TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
01011 QPtrList<ParaInfo> list = info->m_paraList;
01012
01013 for(ParaInfo * item = list.first(); item; item=list.next())
01014 if((pstart+item->start) <= para && (item->start+pstart+item->size) >= para )
01015 if(item->size > 0)
01016 return true;
01017 }
01018 return false;
01019 }
01020
01021 bool CodeEditor::isParaEditable (int para) {
01022
01023 if (para <0)
01024 return false;
01025
01026 TextBlock * tBlock = m_textBlockList.at(para);
01027 if(tBlock)
01028 {
01029 int editStart = tBlock->firstEditableLine();
01030 int editEnd = tBlock->lastEditableLine();
01031 bool hasEditableRange = (editStart > 0 || editEnd < 0) ? true : false;
01032 TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
01033 int pstart = m_textBlockList.findRef(tBlock);
01034 int relativeLine = para - pstart;
01035 QPtrList<ParaInfo> list = info->m_paraList;
01036 for(ParaInfo * item = list.first(); item; item=list.next())
01037 {
01038 if((item->start+pstart) <= para && (item->start+pstart+item->size) >= para)
01039 if(item->isEditable && hasEditableRange)
01040 {
01041 if ( relativeLine >= editStart && relativeLine <= (item->size + editEnd) )
01042 return true;
01043 else
01044 return false;
01045 } else
01046 return item->isEditable;
01047 }
01048 }
01049 return false;
01050 }
01051
01052 void CodeEditor::changeTextBlockHighlighting(TextBlock * tBlock, bool selected) {
01053
01054 if(tBlock)
01055 {
01056 TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
01057 QPtrList<ParaInfo> list = info->m_paraList;
01058 int pstart = m_textBlockList.findRef(tBlock);
01059 for(ParaInfo * item = list.first(); item; item=list.next())
01060 for(int p=(item->start+pstart);p<=(item->start+pstart+item->size);p++)
01061 if(selected)
01062 if(info->isClickable)
01063 setParagraphBackgroundColor(p,getState().selectedColor);
01064 else
01065 setParagraphBackgroundColor(p,getState().nonEditBlockColor);
01066 else if(m_isHighlighted)
01067 setParagraphBackgroundColor(p,item->bgcolor);
01068 else
01069 setParagraphBackgroundColor(p,getState().paperColor);
01070 }
01071
01072 }
01073
01074 void CodeEditor::changeShowHidden (int signal) {
01075
01076 if(signal)
01077 m_showHiddenBlocks = true;
01078 else
01079 m_showHiddenBlocks = false;
01080
01081 rebuildView(m_lastPara);
01082
01083 }
01084
01085
01086 void CodeEditor::changeHighlighting(int signal) {
01087
01088 int total_para = paragraphs()-1;
01089 if(signal) {
01090
01091 m_isHighlighted = true;
01092 for(int para=0;para<total_para;para++)
01093 {
01094 TextBlock * tblock = m_textBlockList.at(para);
01095 changeTextBlockHighlighting(tblock,false);
01096 }
01097
01098
01099 } else {
01100
01101 m_isHighlighted = false;
01102 for(int para=0;para<total_para;para++)
01103 setParagraphBackgroundColor(para,getState().paperColor);
01104 }
01105
01106
01107 if(m_selectedTextBlock)
01108 changeTextBlockHighlighting(m_selectedTextBlock,true);
01109
01110 }
01111
01112 void CodeEditor::contractSelectedParagraph( int paraToRemove ) {
01113 TextBlock * tBlock = m_textBlockList.at(paraToRemove);
01114 if(tBlock)
01115 {
01116 int pstart = m_textBlockList.findRef(tBlock);
01117 TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
01118 QPtrList<ParaInfo> list = info->m_paraList;
01119
01120 bool lowerStartPosition = false;
01121 for(ParaInfo * item = list.first(); item; item=list.next())
01122 {
01123 if(lowerStartPosition)
01124 item->start -= 1;
01125
01126 if((pstart+item->start) <= paraToRemove && (item->start+pstart+item->size) >= paraToRemove)
01127 {
01128 item->size -= 1;
01129
01130
01131
01132 if(item->size < 0)
01133 item->size = 0;
01134 lowerStartPosition = true;
01135 }
01136 }
01137
01138 m_textBlockList.remove(paraToRemove);
01139 }
01140 }
01141
01142 void CodeEditor::expandSelectedParagraph( int priorPara ) {
01143
01144
01145 TextBlock * tBlock = m_textBlockList.at(priorPara);
01146 if(tBlock)
01147 {
01148
01149 m_textBlockList.insert(priorPara,tBlock);
01150 TextBlockInfo *info = (*m_tbInfoMap)[tBlock];
01151 QPtrList<ParaInfo> list = info->m_paraList;
01152 int pstart = m_textBlockList.findRef(tBlock);
01153
01154
01155 bool upStartPosition = false;
01156 for(ParaInfo * item = list.first(); item; item=list.next())
01157 {
01158
01159 if(upStartPosition)
01160 item->start += 1;
01161
01162 if((pstart+item->start) <= priorPara && (item->start+pstart+item->size) >= priorPara)
01163 {
01164 item->size += 1;
01165 cursorPositionChanged(m_lastPara, m_lastPos);
01166 upStartPosition = true;
01167 }
01168 }
01169 }
01170
01171 }
01172
01173 void CodeEditor::contentsMouseMoveEvent ( QMouseEvent * e )
01174 {
01175
01176 int para = paragraphAt(e->pos());
01177
01178 if (para < 0)
01179 return;
01180
01181 TextBlock * tblock = m_textBlockList.at(para);
01182 if (tblock && m_selectedTextBlock != tblock ) {
01183 TextBlockInfo * info = (*m_tbInfoMap)[tblock];
01184
01185
01186
01187 changeTextBlockHighlighting(m_selectedTextBlock,false);
01188
01189
01190 changeTextBlockHighlighting(tblock,true);
01191
01192
01193 getComponentLabel()->setText("<b>"+info->displayName+"</b>");
01194
01195 m_selectedTextBlock = tblock;
01196
01197 if(m_lastTextBlockToBeEdited)
01198 {
01199 updateTextBlockFromText (m_lastTextBlockToBeEdited);
01200 m_lastTextBlockToBeEdited = 0;
01201 }
01202 }
01203
01204
01205
01206 }
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217 void CodeEditor::rebuildView( int startCursorPos ) {
01218
01219 loadFromDocument();
01220
01221
01222
01223 int new_nrof_para = paragraphs() -1;
01224 setCursorPosition((startCursorPos < new_nrof_para ? startCursorPos : 0), 0);
01225
01226 }
01227
01228
01229
01230
01231 #include "codeeditor.moc"