00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <QtGui/QLineEdit>
00015 #include <QtGui/QPushButton>
00016 #include <QtGui/QToolButton>
00017 #include <QtGui/QHBoxLayout>
00018 #include <QtGui/QIcon>
00019 #include <QtGui/QCompleter>
00020 #include <QtGui/QTreeView>
00021 #include <QtGui/QScrollBar>
00022 #include <QtGui/QToolTip>
00023 #include <QtGui/QLabel>
00024
00025
00026 #include "SeExprEdShortEdit.h"
00027 #include "SeExprEdDialog.h"
00028 #include "SeExprEdBrowser.h"
00029 #include "SeExprEdHighlighter.h"
00030 #include "SeExprEdCompletionModel.h"
00031 #include "SeExprEdControlCollection.h"
00032 #include "SeExprEdPopupDocumentation.h"
00033 #include "SeExprEdExpression.h"
00034
00035
00036
00037 static const char *sum_xpm[]={
00038 "16 16 6 1",
00039 "# c None",
00040 ". c None",
00041 "b c #808080",
00042 "d c #010000",
00043 "c c #aaaaaa",
00044 "a c #303030",
00045 "................",
00046 ".#aaaaaaaaaa##..",
00047 ".abbbbbbcbbba...",
00048 ".#abbaaaaabba...",
00049 "..#aabba..aba...",
00050 "....#abba..a#...",
00051 ".....#abba......",
00052 ".....#abba......",
00053 "...##abba...#...",
00054 "...#abba...aa...",
00055 "..#abba...aca...",
00056 ".#abbaaaaabba...",
00057 ".abbbbbbbbbba...",
00058 ".aaaaaaaaaaa#...",
00059 "................",
00060 "................"};
00061
00062
00063 static const char *stop_xpm[] = {
00064 "16 16 4 1",
00065 " c None",
00066 ". c #FF0000",
00067 "+ c #FF8080",
00068 "@ c #FFFFFF",
00069 " ",
00070 " ",
00071 " ...... ",
00072 " ...+++.. ",
00073 " ....@@@... ",
00074 " .....@@@.... ",
00075 " .....@@@.... ",
00076 " .....@@@.... ",
00077 " .....@@@.... ",
00078 " ............ ",
00079 " ....@@@.... ",
00080 " ...@@@... ",
00081 " ....... ",
00082 " ..... ",
00083 " ",
00084 " "};
00085
00086
00087
00088 SeExprEdShortEdit::SeExprEdShortEdit(QWidget* parent, bool expanded)
00089 :QWidget(parent), _context(""), _searchPath("")
00090 {
00091 controlRebuildTimer=new QTimer();
00092
00093 vboxlayout=new QVBoxLayout();
00094 vboxlayout->setMargin(0);
00095 hboxlayout=new QHBoxLayout();
00096 hboxlayout->setMargin(0);
00097
00098
00099 edit=new SeExprEdShortTextEdit(parent);
00100
00101 error=new QLabel();
00102 error->setPixmap(QPixmap(stop_xpm));
00103 error->setHidden(true);
00104
00105 expandButton=new QToolButton;
00106 expandButton->setMinimumSize(20,20);
00107 expandButton->setMaximumSize(20,20);
00108 expandButton->setFocusPolicy(Qt::NoFocus);
00109 if (expanded) expandButton->setArrowType(Qt::DownArrow);
00110 else expandButton->setArrowType(Qt::RightArrow);
00111 connect(expandButton,SIGNAL(clicked()),SLOT(expandPressed()));
00112
00113 QToolButton* button=new QToolButton;
00114 editDetail=button;
00115 button->setIcon(QIcon(QPixmap(sum_xpm)));
00116 hboxlayout->addWidget(expandButton);
00117 hboxlayout->addWidget(edit);
00118 hboxlayout->addWidget(error);
00119 hboxlayout->addWidget(editDetail);
00120
00121 editDetail->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
00122 editDetail->setMinimumSize(20,20);
00123 editDetail->setMaximumSize(20,20);
00124 connect(editDetail,SIGNAL(clicked()),SLOT(detailPressed()));
00125
00126 connect(edit,SIGNAL(editingFinished()),SLOT(textFinished()));
00127
00128 vboxlayout->addLayout(hboxlayout);
00129
00130 controls=0;
00131 if (expanded) expandPressed();
00132
00133 setLayout(vboxlayout);
00134 connect(controlRebuildTimer, SIGNAL(timeout()), SLOT(rebuildControls()));
00135 }
00136
00137 SeExprEdShortEdit::~SeExprEdShortEdit()
00138 {
00139 delete controlRebuildTimer;
00140 }
00141
00142 void SeExprEdShortEdit::setSearchPath(const QString& context, const QString& path)
00143 {
00144 _context = context.toStdString();
00145 _searchPath = path.toStdString();
00146 }
00147
00148 void SeExprEdShortEdit::detailPressed()
00149 {
00150 showDetails(-1);
00151 }
00152
00153 int SeExprEdShortEdit::showDetails(int idx)
00154 {
00155 SeExprEdDialog dialog(0);
00156 dialog.editor->replaceExtras(*edit->completionModel);
00157
00158 dialog.browser->setSearchPath(_context.c_str(), _searchPath.c_str());
00159 dialog.browser->expandAll();
00160 dialog.setExpressionString(getExpressionString());
00161 if (idx >= 0) {
00162 dialog.showEditor(idx);
00163 }
00164
00165 int result = dialog.exec();
00166
00167 if (QDialog::Accepted == result) {
00168 setExpressionString(dialog.getExpressionString());
00169 }
00170
00171 return result;
00172 }
00173
00174 void SeExprEdShortEdit::rebuildControls()
00175 {
00176 if(controls){
00177 bool wasShown=!edit->completer->popup()->isHidden();
00178
00179 bool newVariables=controls->rebuildControls(getExpression(),edit->completionModel->local_variables);
00180 if (controls->numControls()==0)
00181 {
00182 controls->deleteLater();
00183 controls=0;
00184 expandButton->setArrowType(Qt::RightArrow);
00185 }
00186 else vboxlayout->addWidget(controls);
00187 if(newVariables) edit->completer->setModel(edit->completionModel);
00188 if(wasShown) edit->completer->popup()->show();
00189 }
00190 }
00191
00192 void SeExprEdShortEdit::expandPressed()
00193 {
00194 if(controls){
00195
00196 controls->deleteLater();
00197 controls=0;
00198 expandButton->setArrowType(Qt::RightArrow);
00199 }else{
00200 controls=new SeExprEdControlCollection(0,false);
00201
00202 connect(controls,SIGNAL(controlChanged(int)),SLOT(controlChanged(int)));
00203 controlRebuildTimer->setSingleShot(true);
00204 controlRebuildTimer->start(0);
00205 expandButton->setArrowType(Qt::DownArrow);
00206 }
00207 }
00208
00209 void SeExprEdShortEdit::handleTextEdited()
00210 {}
00211
00212 void SeExprEdShortEdit::textFinished()
00213 {
00214 controlRebuildTimer->setSingleShot(true);
00215 controlRebuildTimer->start(0);
00216 checkErrors();
00217 emit exprChanged();
00218 }
00219
00220 void SeExprEdShortEdit::setExpressionString(const std::string& expression)
00221 {
00222 edit->setText(QString(expression.c_str()).replace("\n","\\n"));
00223
00224 controlRebuildTimer->setSingleShot(true);
00225 controlRebuildTimer->start(0);
00226 checkErrors();
00227 emit exprChanged();
00228 }
00229
00230 QString SeExprEdShortEdit::getExpression() const
00231 {
00232 return edit->toPlainText().replace("\\n","\n");
00233 }
00234
00235 std::string SeExprEdShortEdit::getExpressionString()const
00236 {
00237 return getExpression().toStdString();
00238 }
00239
00240 void SeExprEdShortEdit::controlChanged(int id)
00241 {
00242 if(controls){
00243 QString newText=getExpression();
00244 controls->updateText(id,newText);
00245 edit->setText(newText.replace("\n","\\n"));
00246 checkErrors();
00247 emit exprChanged();
00248 }
00249 }
00250
00251 void SeExprEdShortEdit::
00252 clearExtraCompleters()
00253 {
00254 edit->completionModel->clearFunctions();
00255 edit->completionModel->clearVariables();
00256 }
00257
00258 void SeExprEdShortEdit::
00259 registerExtraFunction(const std::string& name,const std::string& docString)
00260 {
00261 edit->completionModel->addFunction(name.c_str(),docString.c_str());
00262 }
00263
00264 void SeExprEdShortEdit::
00265 registerExtraVariable(const std::string& name,const std::string& docString)
00266 {
00267 edit->completionModel->addVariable(name.c_str(),docString.c_str());
00268 }
00269
00270 void SeExprEdShortEdit::
00271 updateCompleter()
00272 {
00273 edit->completer->setModel(edit->completionModel);
00274 }
00275
00276 void SeExprEdShortEdit::
00277 checkErrors()
00278 {
00279 SeExprEdExpression expr(getExpressionString(),true);
00280 bool valid=expr.isValid();
00281 std::string err;
00282 if (!valid)
00283 err = expr.parseError();
00284
00285 hideErrors(valid, err);
00286 }
00287
00288 void SeExprEdShortEdit::
00289 hideErrors(bool hidden, const std::string &err)
00290 {
00291 error->setHidden(hidden);
00292 if (!hidden) {
00293 error->setToolTip(QString::fromStdString(err));
00294 }
00295 }
00296
00297 void SeExprEdShortEdit::
00298 setSimple(bool enabled)
00299 {
00300 edit->setHidden(enabled);
00301 editDetail->setHidden(enabled);
00302 expandButton->setHidden(enabled);
00303 }
00304
00305 void SeExprEdShortEdit::setDetailsMenu(QMenu *menu)
00306 {
00307 editDetail->setMenu(menu);
00308 }
00309
00310 void SeExprEdShortEdit::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
00311 {
00312 edit->setVerticalScrollBarPolicy(policy);
00313 }
00314
00315
00316 SeExprEdShortTextEdit::SeExprEdShortTextEdit(QWidget* parent)
00317 :QTextEdit(parent),editing(false),_tip(0)
00318 {
00319 lastStyleForHighlighter=0;
00320 setMaximumHeight(25);
00321 highlighter=new SeExprEdHighlighter(document());
00322 highlighter->fixStyle(palette());
00323 highlighter->rehighlight();
00324 repaint();
00325
00326
00327 completer=new QCompleter();
00328 completionModel=new SeExprEdCompletionModel(this);
00329 completer->setModel(completionModel);
00330 QTreeView* treePopup=new QTreeView;
00331 completer->setPopup(treePopup);
00332 treePopup->setRootIsDecorated(false);
00333 treePopup->setMinimumWidth(300);
00334 treePopup->setMinimumHeight(50);
00335 treePopup->setItemsExpandable(true);
00336
00337 completer->setWidget(this);
00338 completer->setCompletionMode(QCompleter::PopupCompletion);
00339 completer->setCaseSensitivity(Qt::CaseInsensitive);
00340 QObject::connect(completer,SIGNAL(activated(const QString&)),this,
00341 SLOT(insertCompletion(const QString&)));
00342
00343 }
00344
00345 void SeExprEdShortTextEdit::focusInEvent(QFocusEvent* e)
00346 {
00347
00348 if(completer) completer->setWidget(this);
00349 QTextEdit::focusInEvent(e);
00350 }
00351
00352 void SeExprEdShortTextEdit::focusOutEvent(QFocusEvent* e)
00353 {
00354
00355 finishEdit();
00356 QTextCursor newCursor=textCursor();
00357 newCursor.clearSelection();
00358 setTextCursor(newCursor);
00359 setColor(false);
00360 hideTip();
00361 QTextEdit::focusOutEvent(e);
00362 }
00363
00364 void SeExprEdShortTextEdit::mousePressEvent(QMouseEvent* event)
00365 {
00366 hideTip();
00367 QTextEdit::mousePressEvent(event);
00368 }
00369
00370 void SeExprEdShortTextEdit::mouseDoubleClickEvent(QMouseEvent* event)
00371 {
00372 hideTip();
00373 QTextEdit::mouseDoubleClickEvent(event);
00374 }
00375
00376 void SeExprEdShortTextEdit::paintEvent(QPaintEvent* e){
00377 if(lastStyleForHighlighter!=style()){
00378 lastStyleForHighlighter=style();
00379 highlighter->fixStyle(palette());
00380 highlighter->rehighlight();
00381 }
00382 QTextEdit::paintEvent(e);
00383 }
00384
00385
00386 void SeExprEdShortTextEdit::keyPressEvent( QKeyEvent* e )
00387 {
00388
00389
00390
00391 if(completer && completer->popup()->isVisible()){
00392 switch(e->key()){
00393 case Qt::Key_Enter:case Qt::Key_Return:case Qt::Key_Escape:
00394 case Qt::Key_Tab:case Qt::Key_Backtab:
00395 e->ignore();return;
00396 default:
00397 break;
00398 }
00399 }
00400
00401
00402 if (e->key()==Qt::Key_Return || e->key()==Qt::Key_Enter){
00403 selectAll();
00404 finishEdit();
00405 return;
00406 }else if (e->key()==Qt::Key_Escape){
00407 setText(savedText);
00408 selectAll();
00409 finishEdit();
00410 return;
00411 }else if(e->key()==Qt::Key_Tab){
00412 QWidget::keyPressEvent(e);
00413 return;
00414 }else if(!editing){
00415 editing=true;
00416 setColor(true);
00417 savedText=toPlainText();
00418 }
00419
00420
00421
00422
00423 bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E);
00424 if (!isShortcut)
00425 QTextEdit::keyPressEvent(e);
00426
00427
00428 const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
00429 if (!completer || (ctrlOrShift && e->text().isEmpty()))
00430 return;
00431
00432 bool hasModifier=(e->modifiers()!=Qt::NoModifier) && !ctrlOrShift;
00433
00434
00435 QTextCursor tc=textCursor();
00436 tc.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor);
00437 QString line=tc.selectedText();
00438
00439
00440 static QRegExp completion("^(?:.*[^A-Za-z0-9_$])?((?:\\$[A-Za-z0-9_]*)|[A-Za-z]+[A-Za-z0-9_]*)$");
00441 int index=completion.indexIn(line);
00442 QString completionPrefix;
00443 if(index != -1 && !line.contains('#')){
00444 completionPrefix=completion.cap(1);
00445
00446 }
00447
00448
00449 if(!isShortcut && (hasModifier || e->text().isEmpty() || completionPrefix.length()<1 || index==-1)){
00450 completer->popup()->hide();
00451 }else{
00452
00453
00454 if(completionPrefix!=completer->completionPrefix()){
00455 completer->setCompletionPrefix(completionPrefix);
00456 completer->popup()->setCurrentIndex(completer->completionModel()->index(0,0));
00457 }
00458
00459
00460 QRect cr=cursorRect();
00461 cr.setWidth(2*(completer->popup()->sizeHintForColumn(0)+completer->popup()->sizeHintForColumn(1)
00462 + completer->popup()->verticalScrollBar()->sizeHint().width()));
00463 completer->complete(cr);
00464 hideTip();
00465 return;
00466 }
00467
00468
00469 static QRegExp inFunction("^(?:.*[^A-Za-z0-9_$])?([A-Za-z0-9_]+)\\([^()]*$");
00470 int index2=inFunction.indexIn(line);
00471 if(index2!=-1){
00472 QString functionName=inFunction.cap(1);
00473 QStringList tips=completionModel->getDocString(functionName).split("\n");
00474 QString tip="<b>"+tips[0]+"</b>";
00475 for(int i=1;i<tips.size();i++){
00476 tip+="<br>"+tips[i];
00477 }
00478 showTip(tip);
00479 }else{
00480 hideTip();
00481 }
00482
00483 }
00484
00485 void SeExprEdShortTextEdit::showTip(const QString& string)
00486 {
00487
00488 if(string=="") return;
00489
00490
00491
00492 QRect cr=cursorRect();
00493 cr.setX(0);
00494 cr.setWidth(cr.width()*3);
00495 if(_tip){delete _tip;_tip=0;}
00496 _tip=new SeExprEdPopupDocumentation(this,mapToGlobal(cr.bottomLeft()),string);
00497 }
00498
00499 void SeExprEdShortTextEdit::hideTip()
00500 {
00501 if(_tip) _tip->hide();
00502 }
00503
00504 void SeExprEdShortTextEdit::insertCompletion(const QString &completion)
00505 {
00506 if (completer->widget() != this) return;
00507 QTextCursor tc = textCursor();
00508 int extra = completion.length() - completer->completionPrefix().length();
00509 tc.movePosition(QTextCursor::Left);
00510 tc.movePosition(QTextCursor::EndOfWord);
00511 tc.insertText(completion.right(extra));
00512 if(completion[0]!='$') tc.insertText("(");
00513 setTextCursor(tc);
00514
00515 }
00516
00517 void SeExprEdShortTextEdit::finishEdit()
00518 {
00519 editing=false;
00520 setColor(false);
00521 emit editingFinished();
00522 }
00523
00524
00525
00526 void SeExprEdShortTextEdit::
00527 setColor(bool editing)
00528 {
00529 Q_UNUSED(editing);
00530
00531 }