/*! */ void QFoldPanel::mousePressEvent(QMouseEvent *e) { if ( !editor() || !editor()->languageDefinition() || (e->button() != Qt::LeftButton) ) { QPanel::mousePressEvent(e); return; } QDocument *doc = editor()->document(); QLanguageDefinition *def = editor()->languageDefinition(); int ln = mapRectPosToLine(e->pos()); if ( ln != -1 ){ QDocumentLine b = doc->line(ln); if ( b.hasFlag(QDocumentLine::CollapsedBlockStart) ) def->expand(doc, ln); else //if ( def->blockFlags(doc, ln, 0) & QLanguageDefinition::Collapsible ) collapse checks if it can collapse the line def->collapse(doc, ln); editor()->setFocus(); } else QPanel::mousePressEvent(e); }
/*! */ void QFoldPanel::mousePressEvent(QMouseEvent *e) { if ( !editor() || !editor()->languageDefinition() || (e->button() != Qt::LeftButton) ) { QPanel::mousePressEvent(e); return; } bool act = false; QDocument *doc = editor()->document(); QLanguageDefinition *def = editor()->languageDefinition(); for ( int i = 0; i < m_rects.count(); ++i ) { if ( !m_rects.at(i).contains(e->pos()) ) continue; int ln = m_lines.at(i); QDocumentLine b = doc->line(ln); if ( b.hasFlag(QDocumentLine::CollapsedBlockStart) ) def->expand(doc, ln); else if ( def->blockFlags(doc, ln, 0) & QLanguageDefinition::Collapsible ) def->collapse(doc, ln); act = true; } if ( act ) editor()->setFocus(); else QPanel::mousePressEvent(e); }
bool QFoldPanel::event(QEvent *e) { if (e->type() == QEvent::ToolTip) { QDocument *doc = editor()->document(); QLanguageDefinition *def = doc->languageDefinition(); QHelpEvent* helpEvent = static_cast<QHelpEvent*>(e); int line = mapRectPosToLine(helpEvent->pos()); if ( def && doc && line != -1 && doc->line(line).hasFlag(QDocumentLine::CollapsedBlockStart) ){ QFoldedLineIterator it = def->foldedLineIterator(doc, line); it.incrementUntilBlockEnd(); QString tooltip; if (it.lineNr - line < 16) tooltip = doc->exportAsHtml(doc->cursor(line,0,it.lineNr),true,true); else { tooltip = doc->exportAsHtml(doc->cursor(line,0,line+7),true,true); tooltip.replace("</body></html>",""); tooltip += "<br>...<br>"; tooltip += doc->exportAsHtml(doc->cursor(it.lineNr-7,0,it.lineNr),false); tooltip += "</body></html>"; } if (tooltip.isEmpty()) QToolTip::hideText(); else QToolTip::showText(helpEvent->globalPos(), tooltip); e->setAccepted(true); } } return QWidget::event(e); }
/*! \internal */ void QLineChangePanel::paint(QPainter *p, QEditor *e) { if ( !e || !e->document() ) return; const QFontMetrics fm( e->document()->font() ); int n, posY, // maxCount = 0, as = fm.ascent(), ls = fm.lineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); QString txt; QDocument *d = e->document(); n = d->lineNumber(contentsY); posY = 2 + d->y(n) - contentsY; for ( ; ; ++n ) { //qDebug("n = %i; pos = %i", n, posY); QDocumentLine line = d->line(n); if ( line.isNull() || ((posY - as) > pageBottom) ) break; if ( line.isHidden() ) continue; int span = line.lineSpan(); if ( d->isLineModified(line) ) { p->fillRect(1, posY, 2, ls * span, Qt::yellow); } else if ( d->hasLineEverBeenModified(line) ) { p->fillRect(1, posY, 2, ls * span, Qt::green); } posY += ls * span; } }
/*! \brief Set a search option \param opt option to set \param on whether to enable the option */ void QDocumentSearch::setOption(Option opt, bool on) { if ( on ) m_option |= opt; else m_option &= ~opt; if ( (opt & QDocumentSearch::HighlightAll) && m_highlight.count() ) { QDocument *d = m_editor->document(); if ( m_group != -1 && !on ) { d->clearMatches(m_group); d->flushMatches(m_group); m_group = -1; } else if ( m_group == -1 && on ) { m_group = d->getNextGroupId(); QFormatScheme *f = d->formatScheme(); if ( !f ) f = QDocument::formatFactory(); if ( !f ) { qWarning("No format scheme set to the document and no global default one available.\n" "-> highlighting of search matches disabled."); return; } int sid = f->id("search"); foreach ( const QDocumentCursor& c, m_highlight ) { //QFormatRange r(c.anchorColumnNumber(), c.columnNumber() - c.anchorColumnNumber(), sid); d->addMatch(m_group, c.lineNumber(), c.anchorColumnNumber(), c.columnNumber() - c.anchorColumnNumber(), sid); }
/*! \internal */ bool QLineChangePanel::paint(QPainter *p, QEditor *e) { if ( !e || !e->document() ) return true; int n, posY, as = QFontMetrics(e->document()->font()).ascent(), ls = e->document()->getLineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); QString txt; QDocument *d = e->document(); n = d->lineNumber(contentsY); posY = 2 + d->y(n) - contentsY; for ( ; ; ++n ) { //qDebug("n = %i; pos = %i", n, posY); QDocumentLine line = d->line(n); if ( line.isNull() || ((posY - as) > pageBottom) ) break; if ( line.isHidden() ) continue; int span = line.lineSpan(); if ( d->isLineModified(line) ) { p->fillRect(1, posY, 2, ls * span, QColor(255, 216, 0)); // yellow } else if ( d->hasLineEverBeenModified(line) ) { p->fillRect(1, posY, 2, ls * span, QColor(70, 191, 0)); // green } posY += ls * span; } return true; }
/*! */ void QFoldPanel::paint(QPainter *p, QEditor *e) { QDocument *doc = editor()->document(); QLanguageDefinition *def = e->languageDefinition(); if ( !def || !doc ) { return; } m_rects.clear(); m_lines.clear(); bool bVisible = false; //, // inCursorBlock = false; QDocumentLine block; const QFontMetrics fm(doc->font()); int n, pos, depth = 0, max = doc->lines(), h = fm.height(), ls = fm.lineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); pos = - contentsY; //qDebug("beg pos : %i", pos); for ( n = 0; n < max; ++n ) { if ( pos > pageBottom ) break; block = doc->line(n); if ( block.isHidden() ) { continue; } int len = ls * block.lineSpan(); int flags = def->blockFlags(doc, n, depth); short open = QCE_FOLD_OPEN_COUNT(flags); short close = QCE_FOLD_CLOSE_COUNT(flags); bVisible = ((pos + len) >= 0); int oldDepth = depth; depth -= close; if ( depth < 0 ) depth = 0; depth += open; if ( open ) { if ( flags & QLanguageDefinition::Collapsed ) { int bound = (ls - 8) / 2; int mid = pos + len - ls / 6; // outermost block folded : none of the opening is actually opened depth -= open; if ( bVisible ) { // draw icon if ( bound > 0 && oldDepth > 0 ) { p->drawLine(7, pos, 7, pos + bound); } if ( close ) { p->drawLine(7, pos + 8 + bound, 7, mid); p->drawLine(7, mid, 12, mid); } m_lines << n; m_rects << drawIcon(p, e, 3, pos + bound, true); } int sub = open; //qDebug("%i : +%i", n, open); while ( sub > 0 && ((n + 1) < max) ) { ++n; block = doc->line(n); if ( !block.isHidden() ) { if ( bVisible ) p->drawLine(7, pos + 8 + bound, 7, pos + len); --n; break; } int sflags = def->blockFlags(doc, n, depth + 1); short sopen = QCE_FOLD_OPEN_COUNT(sflags); short sclose = QCE_FOLD_CLOSE_COUNT(sflags); sub -= sclose; if ( sub <= 0 ) break; sub += sopen; } depth += sub; if ( bVisible && depth > 0 ) { if ( close ) p->drawLine(7, mid, 7, pos + len); else p->drawLine(7, pos + 8 + bound, 7, pos + len); } } else { if ( bVisible ) { int bound = (ls - 8) / 2; if ( oldDepth > 0 && bound > 0 ) p->drawLine(7, pos, 7, pos + bound); m_lines << n; m_rects << drawIcon(p, e, 3, pos + bound, false); int mid = pos + len - ls / 6; if ( close ) p->drawLine(7, mid, 12, mid); if ( bound > 0 ) p->drawLine(7, pos + 8 + bound, 7, pos + len); } } } else if ( (oldDepth > 0) && bVisible ) { if ( close ) { int mid = pos + len - ls / 6; p->drawLine(7, pos, 7, mid); p->drawLine(7, mid, 12, mid); if ( depth > 0 ) p->drawLine(7, pos, 7, pos + len); } else { p->drawLine(7, pos, 7, pos + len); } } pos += len; } }
/*! \internal */ void QLineMarkPanel::paint(QPainter *p, QEditor *e) { if ( !e || !e->document() ) return; m_rects.clear(); m_lines.clear(); QDocument *d = e->document(); int maxMarksPerLine = d->maxMarksPerLine(); setFixedWidth(maxMarksPerLine ? maxMarksPerLine * 16 + 2 : 18); const QFontMetrics fm( d->font() ); int n, posY, maxCount = 0, as = fm.ascent(), ls = fm.lineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); QString txt; const QFontMetrics sfm(fontMetrics()); QLineMarksInfoCenter *mic = QLineMarksInfoCenter::instance(); n = d->lineNumber(contentsY); posY = 2 + d->y(n) - contentsY; //qDebug("first = %i; last = %i", first, last); //qDebug("beg pos : %i", posY); //qDebug("<session>"); for ( ; ; ++n ) { //qDebug("n = %i; pos = %i", n, posY); QDocumentLine line = d->line(n); if ( line.isNull() || ((posY - as) > pageBottom) ) break; if ( line.isHidden() ) continue; m_lines << n; m_rects << QRect(0, posY, width(), ls); if ( maxMarksPerLine ) { int count = 1; QList<int> lm = line.marks(); foreach ( int id, lm ) { QPixmap pix = mic->markType(id).icon; if ( pix.isNull() ) continue; int h = qMin(pix.height(), ls), w = qMin(pix.width(), 16), x = count, y = posY + ( (ls - h) >> 1 ); p->drawPixmap(x, y, w, h, pix); count += 16; } } posY += ls * line.lineSpan(); }
/*! */ bool QFoldPanel::paint(QPainter *p, QEditor *e) { QDocument *doc = editor()->document(); QLanguageDefinition *def = e->languageDefinition(); if ( !def || !doc ) { return true; } m_rects.clear(); m_lines.clear(); bool bVisible = false; //, // inCursorBlock = false; int endHighlightLineNr = -1; int pos, max = doc->lines(), ls = doc->getLineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); int xMid = 6, iconSize = 9, yIconOffset = (ls - iconSize) / 2; pos = - contentsY; //qDebug("beg pos : %i", pos); p->save(); QPen linePen(QColor(128,0,128)); linePen.setWidth(3); linePen.setCapStyle(Qt::FlatCap); p->setPen(linePen); QFoldedLineIterator fli = def->foldedLineIterator(doc); for (; fli.lineNr<max; ++fli) { if ( pos > pageBottom ) break; const QDocumentLine &line=fli.line; if ( fli.lineFlagsInvalid() ){ //correct folding when the folding of the current line is invalid //problems: slow (but O(n) like the paint method is anyways), doesn't work if panel is hidden //pro: simple, doesn't correct invalid, but invisible folding (e.g. like folding that is only temporary invalid, until the user writes a closing bracket; otherwise writing $$ would expand every folded $-block) doc->correctFolding(fli.lineNr, doc->lines()); //this will again call paint break; } if ( line.isHidden() ) { continue; } int len = ls * line.lineSpan(); bVisible = ((pos + len) >= 0); if (bVisible) { if ( fli.open ) { if ( line.hasFlag(QDocumentLine::CollapsedBlockStart) ) { // line above icon int topLineEnd = yIconOffset-1; if (topLineEnd > 0 && fli.lineNr <= endHighlightLineNr) p->drawLine(xMid, pos, xMid, pos + topLineEnd); // draw icon m_lines << fli.lineNr; m_rects << drawIcon(p, e, 2, pos + yIconOffset, true, fli.lineNr == m_lastMouseLine); // line below icon int bottomLineStart = yIconOffset + iconSize + 1; if (bottomLineStart < len && fli.lineNr < endHighlightLineNr) p->drawLine(xMid, pos + bottomLineStart, xMid, pos + len); } else { // line above icon int topLineEnd = yIconOffset; if (topLineEnd > 0 && fli.lineNr <= endHighlightLineNr) p->drawLine(xMid, pos, xMid, pos + topLineEnd); // draw icon m_lines << fli.lineNr; m_rects << drawIcon(p, e, 2, pos + yIconOffset, false, fli.lineNr == m_lastMouseLine); if (fli.lineNr == m_lastMouseLine) { QFoldedLineIterator findEnd = fli; findEnd.incrementUntilBlockEnd(); endHighlightLineNr = findEnd.lineNr; } // line below icon int bottomLineStart = yIconOffset + iconSize; if ( bottomLineStart < len && fli.lineNr < endHighlightLineNr) p->drawLine(xMid, pos + bottomLineStart, xMid, pos + len); } } else if (fli.lineNr <= endHighlightLineNr) { if ( fli.lineNr == endHighlightLineNr ) { int mid = pos + len - ls / 6; p->drawLine(xMid, pos, xMid, mid); // line ending here } else { p->drawLine(xMid, pos, xMid, pos + len); // line continues } } } pos += len; } p->restore(); return true; }
/*! */ bool QLineNumberPanel::paint(QPainter *p, QEditor *e) { /* possible Unicode caracter for wrapping arrow : 0x21B3 0x2937 */ QFont f(font()); f.setWeight(QFont::Bold); const QFontMetrics sfm(f); #ifndef WIN32 static const QChar wrappingArrow(0x2937); const QFontMetrics specialSfm(sfm); #else // 0xC4 gives a decent wrapping arrow in Wingdings fonts, availables on all windows systems // this is a hackish fallback to workaround Windows issues with Unicode... static const QChar wrappingArrow(0xC4); QFont specialFont(font()); specialFont.setRawName("Wingdings"); const QFontMetrics specialSfm(specialFont); #endif const int max = e->document()->lines(); const int panelWidth = sfm.width(QString::number(max)) + 5; setFixedWidth(panelWidth); const QFontMetrics fm( e->document()->font() ); int n, posY, as = fm.ascent(), ls = fm.lineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); QString txt; QDocument *d = e->document(); const int cursorLine = e->cursor().lineNumber(); n = d->lineNumber(contentsY); posY = as + 2 + d->y(n) - contentsY; //qDebug("first = %i; last = %i", first, last); //qDebug("beg pos : %i", posY); for ( ; ; ++n ) { //qDebug("n = %i; pos = %i", n, posY); QDocumentLine line = d->line(n); if ( line.isNull() || ((posY - as) > pageBottom) ) break; if ( line.isHidden() ) continue; bool draw = true; if ( !m_verbose ) { draw = !((n + 1) % 10) || !n || line.marks().count(); } txt = QString::number(n + 1); if ( n == cursorLine ) { draw = true; p->save(); QFont f = p->font(); f.setWeight(QFont::Bold); p->setFont(f); } if ( draw ) { p->drawText(width() - 2 - sfm.width(txt), posY, txt); } else { int yOff = posY - (as + 1) + ls / 2; if ( (n + 1) % 5 ) p->drawPoint(width() - 5, yOff); else p->drawLine(width() - 7, yOff, width() - 2, yOff); } if ( line.lineSpan() > 1 ) { #ifdef Q_OS_WIN32 p->save(); specialFont.setBold(n == cursorLine); //todo: only get bold on the current wrapped line p->setFont(specialFont); #endif for ( int i = 1; i < line.lineSpan(); ++i ) { // draw line wrapping indicators //p->drawText(width() - 2 - sfm.width(wrappingArrow), posY + i * ls, wrappingArrow); p->drawText(width() - 1 - specialSfm.width(wrappingArrow), posY + i * ls, wrappingArrow); } #ifdef Q_OS_WIN32 p->restore(); #endif } if ( n == cursorLine ) { p->restore(); } posY += ls * line.lineSpan(); } //p->setPen(Qt::DotLine); //p->drawLine(width()-1, 0, width()-1, pageBottom); //setFixedWidth(sfm.width(txt) + 5); return true; }
/*! */ bool QFoldPanel::paint(QPainter *p, QEditor *e) { QDocument *doc = editor()->document(); QLanguageDefinition *def = e->languageDefinition(); if ( !def || !doc ) { return true; } m_rects.clear(); m_lines.clear(); bool bVisible = false; //, // inCursorBlock = false; int pos, max = doc->lines(), ls = doc->getLineSpacing(), pageBottom = e->viewport()->height(), contentsY = e->verticalOffset(); pos = - contentsY; //qDebug("beg pos : %i", pos); QFoldedLineIterator fli = def->foldedLineIterator(doc); bool oldFolding=false; for (; fli.lineNr<max; ++fli) { if ( pos > pageBottom ) break; const QDocumentLine &line=fli.line; if ( fli.lineFlagsInvalid() ){ //correct folding when the folding of the current line is invalid //problems: slow (but O(n) like the paint method is anyways), doesn't work if panel is hidden //pro: simple, doesn't correct invalid, but invisible folding (e.g. like folding that is only temporary invalid, until the user writes a closing bracket; otherwise writing $$ would expand every folded $-block) doc->correctFolding(fli.lineNr, doc->lines()); //this will again call paint return true; } if ( line.isHidden() ) { continue; } int len = ls * line.lineSpan(); // bool oldFolding = !fli.openParentheses.empty() && fli.openParentheses.first().line!=fli.lineNr; bVisible = ((pos + len) >= 0); if ( fli.open ) { if ( line.hasFlag(QDocumentLine::CollapsedBlockStart) ) { // outermost block folded : none of the opening is actually opened int bound = (ls - 8) / 2; int mid = pos + len - ls / 6; if ( bVisible ) { // draw icon if ( bound > 0 && oldFolding ) { p->drawLine(7, pos, 7, pos + bound); } if ( fli.close ) { p->drawLine(7, pos + 8 + bound, 7, mid); p->drawLine(7, mid, 12, mid); } m_lines << fli.lineNr; m_rects << drawIcon(p, e, 3, pos + bound, true); } int firstParenthesisPos = fli.openParentheses.size() - fli.open; const FoldedParenthesis firstParenthesis = fli.openParentheses[firstParenthesisPos]; while (fli.lineNr<doc->lines() && firstParenthesisPos<fli.openParentheses.size() && fli.openParentheses[firstParenthesisPos] == firstParenthesis){ if (fli.lineNr < doc->lines()-1 && !doc->line(fli.lineNr+1).isHidden()) { if ( bVisible ) p->drawLine(7, pos + 8 + bound, 7, pos + len); break; } ++fli; } if ( bVisible && !fli.openParentheses.empty() ) { if ( fli.close ) p->drawLine(7, mid, 7, pos + len); else p->drawLine(7, pos + 8 + bound, 7, pos + len); } } else { if ( bVisible ) { int bound = (ls - 8) / 2; if ( oldFolding && bound > 0 ) p->drawLine(7, pos, 7, pos + bound); m_lines << fli.lineNr; m_rects << drawIcon(p, e, 3, pos + bound, false); int mid = pos + len - ls / 6; if ( fli.close ) p->drawLine(7, mid, 12, mid); if ( bound > 0 ) p->drawLine(7, pos + 8 + bound, 7, pos + len); } } } else if ( (oldFolding) && bVisible ) { if ( fli.close ) { int mid = pos + len - ls / 6; p->drawLine(7, pos, 7, mid); p->drawLine(7, mid, 12, mid); if ( !fli.openParentheses.empty() ) p->drawLine(7, pos, 7, pos + len); } else { p->drawLine(7, pos, 7, pos + len); } } pos += len; oldFolding=!fli.openParentheses.empty(); } return true; }