File indexing completed on 2025-01-12 06:47:25
0001 /*************************************************************************** 0002 cconsole.cpp - main displaying widget v2 0003 This file is a part of KMuddy distribution. 0004 ------------------- 0005 begin : So Dec 21 2017 0006 copyright : (C) 2002-2017 by Tomas Mecir 0007 email : mecirt@gmail.com 0008 ***************************************************************************/ 0009 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 ***************************************************************************/ 0018 0019 #include "cconsole.h" 0020 0021 #include "cactionmanager.h" 0022 #include "ctextchunk.h" 0023 0024 #include <QAbstractTextDocumentLayout> 0025 #include <QApplication> 0026 #include <QAction> 0027 #include <QDesktopServices> 0028 #include <QGraphicsItemGroup> 0029 #include <QGraphicsSceneHelpEvent> 0030 #include <QGraphicsTextItem> 0031 #include <QScrollBar> 0032 #include <QTextBlock> 0033 #include <QTextBlockFormat> 0034 #include <QTextCursor> 0035 #include <QTextDocument> 0036 #include <QToolTip> 0037 0038 #include <KActionCollection> 0039 #include <KLocalizedString> 0040 0041 0042 class cTextOutputItem : public QGraphicsTextItem { 0043 public: 0044 cTextOutputItem(bool sec) { 0045 isSecondary = sec; 0046 bgcolor = Qt::black; 0047 } 0048 0049 void setBackgroundColor (QColor color) { 0050 bgcolor = color; 0051 } 0052 0053 QPainterPath opaqueArea() const override { 0054 return shape(); 0055 } 0056 0057 void paint (QPainter *painter, const QStyleOptionGraphicsItem *o, QWidget *w) override { 0058 painter->setBrush (bgcolor); 0059 painter->drawRect (boundingRect()); 0060 QGraphicsTextItem::paint (painter, o, w); 0061 } 0062 0063 QRectF boundingRect() const override { 0064 QRectF rect = scene()->sceneRect(); 0065 // add +1 to each side to eliminate the selection box, which we do not want 0066 return QRectF (-1, -1, rect.width() + 2, rect.height() + 2); 0067 } 0068 0069 void updateSize () { 0070 QRectF rect = scene()->sceneRect(); 0071 double w = rect.width(); 0072 if (textWidth() == w) return; // don't update the width if it already is fine - it's an expensive operation 0073 setTextWidth (w); 0074 prepareGeometryChange(); 0075 } 0076 0077 protected: 0078 bool isSecondary; 0079 QColor bgcolor; 0080 }; 0081 0082 class cScrollTextGroup : public QGraphicsItemGroup 0083 { 0084 public: 0085 cScrollTextGroup() { 0086 _percentHeight = 25; 0087 setFlag (QGraphicsItem::ItemClipsChildrenToShape); 0088 } 0089 0090 QRectF boundingRect() const override { 0091 QGraphicsScene *sc = scene(); 0092 if (sc->views().isEmpty()) return QRectF (0, 0, 0, 0); 0093 QGraphicsView *view = sc->views().first(); 0094 double w = view->viewport()->width(); 0095 double h = view->viewport()->height(); 0096 h = h * _percentHeight / 100; 0097 return QRectF (0, 0, w, h); 0098 } 0099 0100 void setPercentHeight (int ph) { 0101 updateSize(); 0102 _percentHeight = ph; 0103 } 0104 0105 int percentHeight () { 0106 return _percentHeight; 0107 } 0108 0109 void updateSize () { 0110 prepareGeometryChange(); 0111 } 0112 0113 protected: 0114 int _percentHeight; 0115 }; 0116 0117 class cConsoleTimestamp : public QTextBlockUserData { 0118 public: 0119 cConsoleTimestamp(QDateTime s) { stamp = s; } 0120 ~cConsoleTimestamp() override{}; 0121 QDateTime stamp; 0122 }; 0123 0124 class cConsoleScene : public QGraphicsScene { 0125 0126 protected: 0127 0128 QString formatTimeStamp (QDateTime timestamp) { 0129 QString stamp = timestamp.toString ("hh:mm:ss"); 0130 0131 int secsago = timestamp.secsTo (QDateTime::currentDateTime()); 0132 if (secsago == 0) //special case: NOW! 0133 stamp += (" (" + i18n ("now") + ")"); 0134 else 0135 { 0136 int minsago = secsago / 60; 0137 int hoursago = minsago / 60; 0138 secsago = secsago % 60; 0139 minsago = minsago % 60; 0140 // FIXME: fix word puzzle 0141 stamp += " ("; 0142 if (hoursago) 0143 stamp += QString::number (hoursago) + ((hoursago == 1) ? i18n ("hour") : i18n ("hours")); 0144 if (minsago && (hoursago < 10)) //don't show minutes if >= 10 hrs 0145 { 0146 if (hoursago) 0147 stamp += " "; 0148 stamp += QString::number (minsago) + " " + ((minsago == 1) ? i18n ("minute") : i18n ("minutes")); 0149 } 0150 if (secsago && (!(hoursago || (minsago >= 5)))) //don't show seconds if >= 5 mins ago 0151 { 0152 if (minsago || hoursago) 0153 stamp += " "; 0154 stamp += QString::number (secsago) + " " + ((secsago == 1) ? i18n ("second") : i18n ("seconds")); 0155 } 0156 stamp += (" " + i18n ("ago") + ")"); 0157 } 0158 return stamp; 0159 } 0160 0161 void helpEvent(QGraphicsSceneHelpEvent *helpEvent) override { 0162 QGraphicsItem *top = itemAt (helpEvent->scenePos(), QTransform()); 0163 if (!top) { 0164 QToolTip::hideText(); 0165 return; 0166 } 0167 cTextOutputItem *text = dynamic_cast<cTextOutputItem *>(top); 0168 if (!text) { 0169 QToolTip::hideText(); 0170 return; // not a text item 0171 } 0172 0173 // get the block at the mouse position 0174 cConsoleTimestamp *stamp = nullptr; 0175 QPointF coord = text->mapFromScene (helpEvent->scenePos()); 0176 QAbstractTextDocumentLayout *layout = text->document()->documentLayout(); 0177 QTextBlock block = text->document()->lastBlock(); 0178 while (block != text->document()->firstBlock()) { 0179 if (layout->blockBoundingRect(block).contains (coord)) { // found it 0180 stamp = dynamic_cast<cConsoleTimestamp *>(block.userData()); 0181 break; 0182 } 0183 block = block.previous(); 0184 } 0185 0186 if (!stamp) { 0187 QToolTip::hideText(); 0188 return; // not in text 0189 } 0190 0191 QString tip = formatTimeStamp (stamp->stamp); 0192 QToolTip::showText(helpEvent->screenPos(), tip); 0193 } 0194 0195 }; 0196 0197 0198 class cConsole::Private { 0199 cConsoleScene scene; 0200 cTextOutputItem *mainText, *scrollText; 0201 cScrollTextGroup *scrollTextGroup; 0202 QTextDocument *text; 0203 0204 int historySize; 0205 QColor bgcolor; 0206 QFont font; 0207 int sess; 0208 int indentChars; 0209 double charWidth, charHeight; 0210 bool wantNewLine; 0211 bool atBottom; 0212 0213 friend class cConsole; 0214 }; 0215 0216 0217 0218 cConsole::cConsole(QWidget *parent) : QGraphicsView(parent) { 0219 d = new Private; 0220 d->sess = -1; 0221 d->charWidth = 12; 0222 d->charHeight = 12; 0223 d->wantNewLine = false; 0224 d->atBottom = true; 0225 d->historySize = 1000; 0226 d->indentChars = 0; 0227 0228 setHorizontalScrollBarPolicy (Qt::ScrollBarAlwaysOff); 0229 setVerticalScrollBarPolicy (Qt::ScrollBarAlwaysOn); 0230 0231 //and connect() slider so that aconsole is shown/hidden as needed 0232 connect (verticalScrollBar (), &QScrollBar::sliderMoved, this, &cConsole::sliderChanged); 0233 connect (verticalScrollBar (), &QScrollBar::valueChanged, this, &cConsole::sliderChanged); 0234 0235 d->text = new QTextDocument; 0236 d->text->setUndoRedoEnabled (false); 0237 // QString stylesheet = "* { white-space: pre-wrap; } a { color: " + QColor (Qt::blue).name() + "; } "; 0238 // d->text->setDefaultStyleSheet (stylesheet); 0239 QTextOption opt; 0240 opt.setWrapMode (QTextOption::WrapAtWordBoundaryOrAnywhere); 0241 d->text->setDefaultTextOption (opt); 0242 0243 //size policy 0244 QSizePolicy qsp (QSizePolicy::Expanding, QSizePolicy::Expanding); 0245 setSizePolicy (qsp); 0246 setFocusPolicy (Qt::NoFocus); 0247 0248 // scene 0249 setScene (&d->scene); 0250 // this needs to be set immediately to prevent an endless recursion 0251 scene()->setSceneRect (0, 0, viewport()->width(), viewport()->height()); 0252 0253 d->mainText = new cTextOutputItem (false); 0254 d->scrollText = new cTextOutputItem (true); 0255 d->scrollTextGroup = new cScrollTextGroup; 0256 d->scene.addItem (d->mainText); 0257 d->scene.addItem (d->scrollTextGroup); 0258 d->scene.addItem (d->scrollText); 0259 connect (d->mainText, &QGraphicsTextItem::linkActivated, this, &cConsole::linkActivated); 0260 connect (d->scrollText, &QGraphicsTextItem::linkActivated, this, &cConsole::linkActivated); 0261 connect (d->mainText, &QGraphicsTextItem::linkHovered, this, &cConsole::linkHovered); 0262 connect (d->scrollText, &QGraphicsTextItem::linkHovered, this, &cConsole::linkHovered); 0263 0264 d->mainText->setDocument (d->text); 0265 // d->mainText->setFiltersChildEvents (true); 0266 d->mainText->setPos (0, 0); 0267 d->mainText->setTextInteractionFlags (Qt::TextBrowserInteraction); 0268 0269 d->scrollTextGroup->setParentItem (d->mainText); 0270 d->scrollTextGroup->setVisible (false); 0271 0272 d->scrollText->setDocument (d->text); 0273 d->scrollText->setParentItem (d->scrollTextGroup); 0274 d->scrollText->setPos (0, 0); 0275 d->scrollText->setTextInteractionFlags (Qt::TextBrowserInteraction); 0276 0277 d->scene.setFocusItem (d->mainText); 0278 connect (&d->scene, &QGraphicsScene::changed, this, &cConsole::sceneChanged); 0279 0280 //background color 0281 setDefaultBkColor (Qt::black); 0282 0283 //context menu 0284 setContextMenuPolicy (Qt::ActionsContextMenu); 0285 KActionCollection *acol = cActionManager::self()->getACol(); 0286 QAction *showmenubar = acol->action ("ShowMenuBar"); 0287 QAction *fullscreenmode = acol->action ("SetFullScreen"); 0288 QAction *clipcopy = acol->action ("ClipboardCopy"); 0289 QAction *pastemenu = acol->action ("PasteMenu"); 0290 QAction *sep1 = new QAction (this); 0291 QAction *sep2 = new QAction (this); 0292 sep1->setSeparator (true); 0293 sep2->setSeparator (true); 0294 if (clipcopy) addAction (clipcopy); 0295 if (pastemenu) addAction (pastemenu); 0296 addAction (sep1); 0297 if (showmenubar) addAction (showmenubar); 0298 addAction (sep2); 0299 if (fullscreenmode) addAction (fullscreenmode); 0300 0301 setFont (QFontDatabase::systemFont (QFontDatabase::FixedFont)); //default system fixed font 0302 viewport()->setCursor (Qt::IBeamCursor); 0303 0304 forceBeginOfLine (); 0305 fixupOutput(true); 0306 } 0307 0308 cConsole::~cConsole() { 0309 setScene (nullptr); // needed to prevent crashes in the destructor 0310 0311 delete d->scrollText; 0312 delete d->mainText; 0313 delete d->text; 0314 delete d; 0315 } 0316 0317 void cConsole::setSession (int s) { 0318 d->sess = s; 0319 } 0320 0321 void cConsole::setFont (QFont f) { 0322 d->font = f; 0323 d->text->setDefaultFont (d->font); 0324 0325 QFontMetrics fm (f); 0326 d->charWidth = fm.horizontalAdvance ("m"); 0327 d->charHeight = fm.lineSpacing() + 2; 0328 0329 fixupOutput(true); 0330 } 0331 0332 QFont cConsole::font () { 0333 return d->font; 0334 } 0335 0336 void cConsole::setDefaultBkColor (QColor color) { 0337 0338 d->bgcolor = color; 0339 QPalette pal = palette(); 0340 pal.setColor (backgroundRole(), d->bgcolor); 0341 pal.setColor (QPalette::Base, d->bgcolor); 0342 setPalette (pal); 0343 setBackgroundRole (QPalette::Base); 0344 d->mainText->setBackgroundColor (color); 0345 d->scrollText->setBackgroundColor (color); 0346 update(); 0347 } 0348 0349 QColor cConsole::defaultBkColor () { 0350 return d->bgcolor; 0351 } 0352 0353 void cConsole::setScrollTextVisible (bool vis) 0354 { 0355 d->scrollTextGroup->setVisible (vis); 0356 } 0357 0358 void cConsole::sliderChanged (int val) 0359 { 0360 int maxval = verticalScrollBar()->maximum (); 0361 0362 // if we're very close to the bottom, push the slider to the bottom 0363 // this fixes an off-by-one issue where scrollback would open when switching between tabs due to rounding issues 0364 if ((val < maxval) && (val >= maxval - 2)) { 0365 verticalScrollBar()->setValue (maxval); 0366 return; 0367 } 0368 0369 d->atBottom = (val >= maxval); 0370 bool vis = (val < maxval); 0371 setScrollTextVisible (vis); 0372 } 0373 0374 void cConsole::sceneChanged (const QList<QRectF> &) 0375 { 0376 // move back to the bottom if we were 0377 if (!d->atBottom) return; 0378 QScrollBar *sb = verticalScrollBar(); 0379 sb->setValue (sb->maximum()); 0380 } 0381 0382 void cConsole::setScrollTextSize (int aconsize) 0383 { 0384 d->scrollTextGroup->setPercentHeight (aconsize); 0385 adjustScrollBack(); 0386 } 0387 0388 void cConsole::setIndentation (int val) { 0389 0390 d->indentChars = val; 0391 } 0392 0393 void cConsole::setEnableBlinking (bool /*value*/) { 0394 // TODO 0395 } 0396 0397 int cConsole::curRows() { 0398 return height() / d->charHeight; 0399 } 0400 0401 int cConsole::curCols() { 0402 if (d->charWidth <= 0) return 0; 0403 return width() / d->charWidth; 0404 } 0405 0406 void cConsole::forceEmitSize () { 0407 emit dimensionsChanged (curCols(), curRows()); 0408 } 0409 0410 void cConsole::dumpBuffer (bool /*fromcurrent*/, QFile &file, char dumpType) { 0411 QString contents; 0412 // TODO: support 'fromcurrent' 0413 if ((dumpType == TRANSCRIPT_PLAIN) || (dumpType == TRANSCRIPT_ANSI)) 0414 contents = d->text->toPlainText(); 0415 else if (dumpType == TRANSCRIPT_HTML) 0416 contents = d->text->toHtml(); 0417 file.write (contents.toLocal8Bit()); 0418 } 0419 0420 void cConsole::setHistorySize (int size) { 0421 d->historySize = size; 0422 } 0423 0424 // grab all the words from the last 100 lines that meet the prefix/length criteria 0425 QStringList cConsole::words (QString prefix, int minLength) { 0426 QStringList res; 0427 0428 int lineLimit = 100; 0429 int lines = 0; 0430 QTextBlock block = d->text->lastBlock(); 0431 while ((block != d->text->firstBlock()) && (lines < lineLimit)) { 0432 lines += block.lineCount(); 0433 QString text = block.text(); 0434 // split the text into words 0435 QStringList words = text.split (QRegExp ("[\\s\\.\\,\\(\\)\\[\\]\\?\\!\\:\\;\"\']")); 0436 //store words that meet the requirements 0437 for (QString word : words) { 0438 if (word.length() < minLength) continue; 0439 if ((!prefix.isEmpty()) && (!word.startsWith (prefix, Qt::CaseInsensitive))) continue; 0440 // case-sensitive comparison here, so we store all the used upper/lowercase variants 0441 if (res.contains (word)) continue; 0442 0443 res.push_back (word); 0444 } 0445 0446 block = block.previous(); 0447 } 0448 0449 // We intentionally don't sort the list. 0450 return res; 0451 } 0452 0453 void cConsole::clear () { 0454 d->text->clear(); 0455 update(); 0456 } 0457 0458 void cConsole::addLine (cTextChunk *chunk) { 0459 addNewText (chunk, true); 0460 } 0461 0462 void cConsole::addText (cTextChunk *chunk) { 0463 addNewText (chunk, false); 0464 } 0465 0466 int cConsole::totalLines() { 0467 return d->text->lineCount(); 0468 } 0469 0470 void cConsole::addNewText (cTextChunk *chunk, bool endTheLine) 0471 { 0472 QTextCursor cursor (d->text); 0473 0474 cursor.beginEditBlock(); 0475 cursor.movePosition (QTextCursor::End); 0476 if (chunk) { 0477 if (d->wantNewLine) { 0478 cursor.insertBlock (); 0479 cursor.block().layout()->setCacheEnabled (true); 0480 cConsoleTimestamp *stamp = new cConsoleTimestamp(chunk->getTimeStamp()); 0481 cursor.block().setUserData (stamp); // this will delete the stamp 0482 d->wantNewLine = false; 0483 QTextBlockFormat bformat = cursor.blockFormat(); 0484 bformat.setForeground (Qt::lightGray); 0485 bformat.setProperty (QTextFormat::FramePadding, 1); 0486 bformat.setLineHeight (2, QTextBlockFormat::LineDistanceHeight); 0487 double px = d->indentChars * d->charWidth; // 0 if no indentation is to happen 0488 bformat.setLeftMargin (px); 0489 bformat.setTextIndent (-1 * px); 0490 cursor.setBlockFormat (bformat); 0491 } 0492 chunk->insertToDocument (cursor); 0493 } 0494 cursor.endEditBlock(); 0495 if (endTheLine) d->wantNewLine = true; 0496 0497 while (totalLines() > d->historySize) { 0498 // check the height of the first block; if removing it won't put us below the history limit, remove it 0499 QTextBlock fblock = d->text->firstBlock(); 0500 int flines = fblock.lineCount(); 0501 if (totalLines() - flines < d->historySize) break; 0502 0503 // determine the distance between the blocks ... can't just use the height of the bounding block, as that doesn't take spacing into account 0504 QTextBlock fnextblock = fblock.next(); 0505 QRectF rect1 = d->text->documentLayout()->blockBoundingRect (fblock); 0506 QRectF rect2 = d->text->documentLayout()->blockBoundingRect (fnextblock); 0507 int fheight = rect2.top() - rect1.top(); 0508 0509 cursor = QTextCursor (fblock); 0510 cursor.select (QTextCursor::BlockUnderCursor); 0511 cursor.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor); // need to move, otherwise the empty block is kept 0512 cursor.removeSelectedText(); 0513 0514 // scroll accordingly if needed 0515 QScrollBar *bar = verticalScrollBar(); 0516 if (!d->atBottom) bar->setValue (bar->value() - fheight); 0517 } 0518 0519 fixupOutput(false); 0520 } 0521 0522 void cConsole::forceBeginOfLine () { 0523 addNewText (nullptr, true); 0524 } 0525 0526 void cConsole::expireNamedLinks (const QString & /*name*/) { 0527 // TODO 0528 } 0529 0530 void cConsole::addSelectionToClipboard (QClipboard::Mode clipboardMode) { 0531 QString selection = d->mainText->textCursor().selectedText(); 0532 if (!selection.size()) return; 0533 selection = selection.replace (QChar::ParagraphSeparator, '\n'); 0534 QApplication::clipboard()->setText (selection, clipboardMode); 0535 } 0536 0537 void cConsole::lineUp () { 0538 QScrollBar *bar = verticalScrollBar(); 0539 int by = bar->singleStep(); 0540 bar->setValue (bar->value() - by); 0541 } 0542 0543 void cConsole::lineDown () { 0544 QScrollBar *bar = verticalScrollBar(); 0545 int by = bar->singleStep(); 0546 bar->setValue (bar->value() + by); 0547 } 0548 0549 void cConsole::pageUp () { 0550 QScrollBar *bar = verticalScrollBar(); 0551 int by = bar->pageStep() * (100 - d->scrollTextGroup->percentHeight()) / 100; // deduct backview size 0552 bar->setValue (bar->value() - by); 0553 } 0554 0555 void cConsole::pageDown () { 0556 QScrollBar *bar = verticalScrollBar(); 0557 int by = bar->pageStep() * (100 - d->scrollTextGroup->percentHeight()) / 100; // deduct backview size 0558 bar->setValue (bar->value() + by); 0559 } 0560 0561 void cConsole::resizeEvent (QResizeEvent *) 0562 { 0563 fixupOutput(true); 0564 } 0565 0566 // this is needed to resize the text display at startup 0567 bool cConsole::viewportEvent(QEvent *event) 0568 { 0569 if (event->type() == QEvent::Resize) 0570 fixupOutput(true); 0571 return QGraphicsView::viewportEvent (event); 0572 } 0573 0574 0575 void cConsole::adjustScrollBack () 0576 { 0577 // move the scrollback to its desired position 0578 int h = d->scrollTextGroup->boundingRect().height(); 0579 QPointF scenepos = mapToScene (0, height() - h); 0580 // don't exceed the scene height 0581 double diff = scenepos.y() + h - d->scene.height(); 0582 if (diff > 0) scenepos.setY (scenepos.y() - diff); 0583 // and shift the text viewer 0584 double ty = d->scrollText->boundingRect().height() - h; 0585 0586 d->scrollTextGroup->setPos (scenepos); 0587 d->scrollText->setPos (0, -ty); 0588 } 0589 0590 void cConsole::scrollContentsBy (int dx, int dy) 0591 { 0592 QGraphicsView::scrollContentsBy (dx, dy); 0593 0594 adjustScrollBack(); 0595 } 0596 0597 void cConsole::fixupOutput (bool sizeChanged) 0598 { 0599 double h = max ((qreal) viewport()->height(), d->text->documentLayout()->documentSize().height()); 0600 scene()->setSceneRect (0, 0, viewport()->width(), h); 0601 0602 sceneChanged(); 0603 d->mainText->updateSize(); 0604 d->scrollText->updateSize(); 0605 adjustScrollBack (); 0606 0607 if (sizeChanged) 0608 forceEmitSize (); 0609 } 0610 0611 void cConsole::linkHovered (const QString &link) 0612 { 0613 viewport()->setCursor (link.isEmpty() ? Qt::IBeamCursor : Qt::PointingHandCursor); 0614 } 0615 0616 void cConsole::linkActivated (const QString &link) 0617 { 0618 // TODO - menus and such, need to encode them in the level text. For now we just use plain text. 0619 // see old code below for menu handling - except that we don't have the chunk pointer 0620 0621 // get the first two words, they are iscommand/toprompt 0622 int pos = link.indexOf(' '); 0623 if (pos < 0) return; 0624 QString w1 = link.left(pos); 0625 QString ll = link.mid(pos + 1); 0626 pos = ll.indexOf(' '); 0627 QString w2 = ll.left(pos); 0628 QString cmd = ll.mid(pos + 1); 0629 0630 if (w1 == "link") { 0631 // URL link 0632 QDesktopServices::openUrl (QUrl (cmd)); 0633 return; 0634 } 0635 0636 if (w2 == "prompt") 0637 emit promptCommand (cmd); 0638 else 0639 emit sendCommand (cmd); 0640 } 0641 0642 0643 0644 /* 0645 void cConsole::activateLink (chunkLink *link, const QPoint &point) 0646 { 0647 //two modes of operation, depending on whether this is a command-link or a URL-link 0648 if (link->isCommand()) 0649 { 0650 QString cmd = link->target(); 0651 bool toprompt = link->toPrompt(); 0652 bool ismenu = link->isMenu(); 0653 if (ismenu) 0654 { 0655 //get rid of old menu, if any 0656 delete linkMenu; 0657 0658 link->parseMenu(); 0659 0660 //create the menu 0661 menuChunk = link; 0662 linkMenu = new KMenu (this); 0663 0664 //insert all the items 0665 list<menuItem>::const_iterator it; 0666 for (it = menuChunk->menu().begin(); it != menuChunk->menu().end(); ++it) 0667 linkMenu->addAction ((*it).caption); 0668 connect (linkMenu, SIGNAL (triggered (QAction *)), this, SLOT (linkMenuItemHandler (QAction *))); 0669 0670 linkMenu->popup (point); 0671 } 0672 else 0673 { 0674 if (toprompt) 0675 emit promptCommand (cmd); 0676 else 0677 emit sendCommand (cmd); 0678 } 0679 } 0680 else 0681 { 0682 QString url = link->target(); 0683 KToolInvocation::invokeBrowser (url); 0684 } 0685 } 0686 0687 void cConsole::linkMenuItemHandler (QAction *item) 0688 { 0689 if (!linkMenu) return; 0690 int idx = linkMenu->actions().indexOf (item); 0691 if (idx == -1) return; // not found 0692 bool toprompt = menuChunk->toPrompt(); 0693 list<menuItem>::const_iterator it; 0694 QString cmd; 0695 it = menuChunk->menu().begin(); 0696 for (int i = 0; i < idx; i++) 0697 ++it; 0698 cmd = (*it).command; 0699 if (toprompt) 0700 emit promptCommand (cmd); 0701 else 0702 emit sendCommand (cmd); 0703 0704 linkMenu = 0; 0705 menuChunk = 0; 0706 } 0707 */ 0708 0709 #include "moc_cconsole.cpp"