diff options
Diffstat (limited to 'kate/part/kateviewhelpers.cpp')
-rw-r--r-- | kate/part/kateviewhelpers.cpp | 1205 |
1 files changed, 1205 insertions, 0 deletions
diff --git a/kate/part/kateviewhelpers.cpp b/kate/part/kateviewhelpers.cpp new file mode 100644 index 000000000..4ca753486 --- /dev/null +++ b/kate/part/kateviewhelpers.cpp @@ -0,0 +1,1205 @@ +/* This file is part of the KDE libraries + Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org> + Copyright (C) 2001 Anders Lund <anders@alweb.dk> + Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kateviewhelpers.h" +#include "kateviewhelpers.moc" + +#include "../interfaces/document.h" +#include "../interfaces/katecmd.h" +#include "kateattribute.h" +#include "katecodefoldinghelpers.h" +#include "kateconfig.h" +#include "katedocument.h" +#include "katefactory.h" +#include "katerenderer.h" +#include "kateview.h" +#include "kateviewinternal.h" + +#include <kapplication.h> +#include <kglobalsettings.h> +#include <klocale.h> +#include <knotifyclient.h> +#include <kglobal.h> +#include <kcharsets.h> +#include <kpopupmenu.h> + +#include <qcursor.h> +#include <qpainter.h> +#include <qpopupmenu.h> +#include <qstyle.h> +#include <qtimer.h> +#include <qwhatsthis.h> +#include <qregexp.h> +#include <qtextcodec.h> + +#include <math.h> + +#include <kdebug.h> + +//BEGIN KateScrollBar +KateScrollBar::KateScrollBar (Orientation orientation, KateViewInternal* parent, const char* name) + : QScrollBar (orientation, parent->m_view, name) + , m_middleMouseDown (false) + , m_view(parent->m_view) + , m_doc(parent->m_doc) + , m_viewInternal(parent) + , m_topMargin(-1) + , m_bottomMargin(-1) + , m_savVisibleLines(0) + , m_showMarks(false) +{ + connect(this, SIGNAL(valueChanged(int)), SLOT(sliderMaybeMoved(int))); + connect(m_doc, SIGNAL(marksChanged()), this, SLOT(marksChanged())); + + m_lines.setAutoDelete(true); +} + +void KateScrollBar::mousePressEvent(QMouseEvent* e) +{ + if (e->button() == MidButton) + m_middleMouseDown = true; + + QScrollBar::mousePressEvent(e); + + redrawMarks(); +} + +void KateScrollBar::mouseReleaseEvent(QMouseEvent* e) +{ + QScrollBar::mouseReleaseEvent(e); + + m_middleMouseDown = false; + + redrawMarks(); +} + +void KateScrollBar::mouseMoveEvent(QMouseEvent* e) +{ + QScrollBar::mouseMoveEvent(e); + + if (e->state() | LeftButton) + redrawMarks(); +} + +void KateScrollBar::paintEvent(QPaintEvent *e) +{ + QScrollBar::paintEvent(e); + redrawMarks(); +} + +void KateScrollBar::resizeEvent(QResizeEvent *e) +{ + QScrollBar::resizeEvent(e); + recomputeMarksPositions(); +} + +void KateScrollBar::styleChange(QStyle &s) +{ + QScrollBar::styleChange(s); + m_topMargin = -1; + recomputeMarksPositions(); +} + +void KateScrollBar::valueChange() +{ + QScrollBar::valueChange(); + redrawMarks(); +} + +void KateScrollBar::rangeChange() +{ + QScrollBar::rangeChange(); + recomputeMarksPositions(); +} + +void KateScrollBar::marksChanged() +{ + recomputeMarksPositions(true); +} + +void KateScrollBar::redrawMarks() +{ + if (!m_showMarks) + return; + + QPainter painter(this); + QRect rect = sliderRect(); + for (QIntDictIterator<QColor> it(m_lines); it.current(); ++it) + { + if (it.currentKey() < rect.top() || it.currentKey() > rect.bottom()) + { + painter.setPen(*it.current()); + painter.drawLine(0, it.currentKey(), width(), it.currentKey()); + } + } +} + +void KateScrollBar::recomputeMarksPositions(bool forceFullUpdate) +{ + if (m_topMargin == -1) + watchScrollBarSize(); + + m_lines.clear(); + m_savVisibleLines = m_doc->visibleLines(); + + int realHeight = frameGeometry().height() - m_topMargin - m_bottomMargin; + + QPtrList<KTextEditor::Mark> marks = m_doc->marks(); + KateCodeFoldingTree *tree = m_doc->foldingTree(); + + for (KTextEditor::Mark *mark = marks.first(); mark; mark = marks.next()) + { + uint line = mark->line; + + if (tree) + { + KateCodeFoldingNode *node = tree->findNodeForLine(line); + + while (node) + { + if (!node->isVisible()) + line = tree->getStartLine(node); + node = node->getParentNode(); + } + } + + line = m_doc->getVirtualLine(line); + + double d = (double)line / (m_savVisibleLines - 1); + m_lines.insert(m_topMargin + (int)(d * realHeight), + new QColor(KateRendererConfig::global()->lineMarkerColor((KTextEditor::MarkInterface::MarkTypes)mark->type))); + } + + if (forceFullUpdate) + update(); + else + redrawMarks(); +} + +void KateScrollBar::watchScrollBarSize() +{ + int savMax = maxValue(); + setMaxValue(0); + QRect rect = sliderRect(); + setMaxValue(savMax); + + m_topMargin = rect.top(); + m_bottomMargin = frameGeometry().height() - rect.bottom(); +} + +void KateScrollBar::sliderMaybeMoved(int value) +{ + if (m_middleMouseDown) + emit sliderMMBMoved(value); +} +//END + +//BEGIN KateCmdLnWhatsThis +class KateCmdLnWhatsThis : public QWhatsThis +{ + public: + KateCmdLnWhatsThis( KateCmdLine *parent ) + : QWhatsThis( parent ) + , m_parent( parent ) {;} + + QString text( const QPoint & ) + { + QString beg = "<qt background=\"white\"><div><table width=\"100%\"><tr><td bgcolor=\"brown\"><font color=\"white\"><b>Help: <big>"; + QString mid = "</big></b></font></td></tr><tr><td>"; + QString end = "</td></tr></table></div><qt>"; + + QString t = m_parent->text(); + QRegExp re( "\\s*help\\s+(.*)" ); + if ( re.search( t ) > -1 ) + { + QString s; + // get help for command + QString name = re.cap( 1 ); + if ( name == "list" ) + { + return beg + i18n("Available Commands") + mid + + KateCmd::self()->cmds().join(" ") + + i18n("<p>For help on individual commands, do <code>'help <command>'</code></p>") + + end; + } + else if ( ! name.isEmpty() ) + { + Kate::Command *cmd = KateCmd::self()->queryCommand( name ); + if ( cmd ) + { + if ( cmd->help( (Kate::View*)m_parent->parentWidget(), name, s ) ) + return beg + name + mid + s + end; + else + return beg + name + mid + i18n("No help for '%1'").arg( name ) + end; + } + else + return beg + mid + i18n("No such command <b>%1</b>").arg(name) + end; + } + } + + return beg + mid + i18n( + "<p>This is the Katepart <b>command line</b>.<br>" + "Syntax: <code><b>command [ arguments ]</b></code><br>" + "For a list of available commands, enter <code><b>help list</b></code><br>" + "For help for individual commands, enter <code><b>help <command></b></code></p>") + + end; + } + + private: + KateCmdLine *m_parent; +}; +//END KateCmdLnWhatsThis + +//BEGIN KateCmdLineFlagCompletion +/** + * This class provide completion of flags. It shows a short description of + * each flag, and flags are appended. + */ +class KateCmdLineFlagCompletion : public KCompletion +{ + public: + KateCmdLineFlagCompletion() {;} + + QString makeCompletion( const QString & string ) + { + return QString::null; + } + +}; +//END KateCmdLineFlagCompletion + +//BEGIN KateCmdLine +KateCmdLine::KateCmdLine (KateView *view) + : KLineEdit (view) + , m_view (view) + , m_msgMode (false) + , m_histpos( 0 ) + , m_cmdend( 0 ) + , m_command( 0L ) + , m_oldCompletionObject( 0L ) +{ + connect (this, SIGNAL(returnPressed(const QString &)), + this, SLOT(slotReturnPressed(const QString &))); + + completionObject()->insertItems (KateCmd::self()->cmds()); + setAutoDeleteCompletionObject( false ); + m_help = new KateCmdLnWhatsThis( this ); +} + +void KateCmdLine::slotReturnPressed ( const QString& text ) +{ + + // silently ignore leading space + uint n = 0; + while( text[n].isSpace() ) + n++; + + QString cmd = text.mid( n ); + + // Built in help: if the command starts with "help", [try to] show some help + if ( cmd.startsWith( "help" ) ) + { + m_help->display( m_help->text( QPoint() ), mapToGlobal(QPoint(0,0)) ); + clear(); + KateCmd::self()->appendHistory( cmd ); + m_histpos = KateCmd::self()->historyLength(); + m_oldText = QString (); + return; + } + + if (cmd.length () > 0) + { + Kate::Command *p = KateCmd::self()->queryCommand (cmd); + + m_oldText = cmd; + m_msgMode = true; + + if (p) + { + QString msg; + + if (p->exec (m_view, cmd, msg)) + { + KateCmd::self()->appendHistory( cmd ); + m_histpos = KateCmd::self()->historyLength(); + m_oldText = QString (); + + if (msg.length() > 0) + setText (i18n ("Success: ") + msg); + else + setText (i18n ("Success")); + } + else + { + if (msg.length() > 0) + setText (i18n ("Error: ") + msg); + else + setText (i18n ("Command \"%1\" failed.").arg (cmd)); + KNotifyClient::beep(); + } + } + else + { + setText (i18n ("No such command: \"%1\"").arg (cmd)); + KNotifyClient::beep(); + } + } + + // clean up + if ( m_oldCompletionObject ) + { + KCompletion *c = completionObject(); + setCompletionObject( m_oldCompletionObject ); + m_oldCompletionObject = 0; + delete c; + c = 0; + } + m_command = 0; + m_cmdend = 0; + + m_view->setFocus (); + QTimer::singleShot( 4000, this, SLOT(hideMe()) ); +} + +void KateCmdLine::hideMe () // unless i have focus ;) +{ + if ( isVisibleTo(parentWidget()) && ! hasFocus() ) { + m_view->toggleCmdLine (); + } +} + +void KateCmdLine::focusInEvent ( QFocusEvent *ev ) +{ + if (m_msgMode) + { + m_msgMode = false; + setText (m_oldText); + selectAll(); + } + + KLineEdit::focusInEvent (ev); +} + +void KateCmdLine::keyPressEvent( QKeyEvent *ev ) +{ + if (ev->key() == Key_Escape) + { + m_view->setFocus (); + hideMe(); + } + else if ( ev->key() == Key_Up ) + fromHistory( true ); + else if ( ev->key() == Key_Down ) + fromHistory( false ); + + uint cursorpos = cursorPosition(); + KLineEdit::keyPressEvent (ev); + + // during typing, let us see if we have a valid command + if ( ! m_cmdend || cursorpos <= m_cmdend ) + { + QChar c; + if ( ! ev->text().isEmpty() ) + c = ev->text()[0]; + + if ( ! m_cmdend && ! c.isNull() ) // we have no command, so lets see if we got one + { + if ( ! c.isLetterOrNumber() && c != '-' && c != '_' ) + { + m_command = KateCmd::self()->queryCommand( text().stripWhiteSpace() ); + if ( m_command ) + { + //kdDebug(13025)<<"keypress in commandline: We have a command! "<<m_command<<". text is '"<<text()<<"'"<<endl; + // if the typed character is ":", + // we try if the command has flag completions + m_cmdend = cursorpos; + //kdDebug(13025)<<"keypress in commandline: Set m_cmdend to "<<m_cmdend<<endl; + } + else + m_cmdend = 0; + } + } + else // since cursor is inside the command name, we reconsider it + { + kdDebug(13025)<<"keypress in commandline: \\W -- text is "<<text()<<endl; + m_command = KateCmd::self()->queryCommand( text().stripWhiteSpace() ); + if ( m_command ) + { + //kdDebug(13025)<<"keypress in commandline: We have a command! "<<m_command<<endl; + QString t = text(); + m_cmdend = 0; + bool b = false; + for ( ; m_cmdend < t.length(); m_cmdend++ ) + { + if ( t[m_cmdend].isLetter() ) + b = true; + if ( b && ( ! t[m_cmdend].isLetterOrNumber() && t[m_cmdend] != '-' && t[m_cmdend] != '_' ) ) + break; + } + + if ( c == ':' && cursorpos == m_cmdend ) + { + // check if this command wants to complete flags + //kdDebug(13025)<<"keypress in commandline: Checking if flag completion is desired!"<<endl; + } + } + else + { + // clean up if needed + if ( m_oldCompletionObject ) + { + KCompletion *c = completionObject(); + setCompletionObject( m_oldCompletionObject ); + m_oldCompletionObject = 0; + delete c; + c = 0; + } + + m_cmdend = 0; + } + } + + // if we got a command, check if it wants to do semething. + if ( m_command ) + { + //kdDebug(13025)<<"Checking for CommandExtension.."<<endl; + Kate::CommandExtension *ce = dynamic_cast<Kate::CommandExtension*>(m_command); + if ( ce ) + { + KCompletion *cmpl = ce->completionObject( text().left( m_cmdend ).stripWhiteSpace(), m_view ); + if ( cmpl ) + { + // save the old completion object and use what the command provides + // instead. We also need to prepend the current command name + flag string + // when completion is done + //kdDebug(13025)<<"keypress in commandline: Setting completion object!"<<endl; + if ( ! m_oldCompletionObject ) + m_oldCompletionObject = completionObject(); + + setCompletionObject( cmpl ); + } + } + } + } + else if ( m_command )// check if we should call the commands processText() + { + Kate::CommandExtension *ce = dynamic_cast<Kate::CommandExtension*>( m_command ); + if ( ce && ce->wantsToProcessText( text().left( m_cmdend ).stripWhiteSpace() ) + && ! ( ev->text().isNull() || ev->text().isEmpty() ) ) + ce->processText( m_view, text() ); + } +} + +void KateCmdLine::fromHistory( bool up ) +{ + if ( ! KateCmd::self()->historyLength() ) + return; + + QString s; + + if ( up ) + { + if ( m_histpos > 0 ) + { + m_histpos--; + s = KateCmd::self()->fromHistory( m_histpos ); + } + } + else + { + if ( m_histpos < ( KateCmd::self()->historyLength() - 1 ) ) + { + m_histpos++; + s = KateCmd::self()->fromHistory( m_histpos ); + } + else + { + m_histpos = KateCmd::self()->historyLength(); + setText( m_oldText ); + } + } + if ( ! s.isEmpty() ) + { + // Select the argument part of the command, so that it is easy to overwrite + setText( s ); + static QRegExp reCmd = QRegExp(".*[\\w\\-]+(?:[^a-zA-Z0-9_-]|:\\w+)(.*)"); + if ( reCmd.search( text() ) == 0 ) + setSelection( text().length() - reCmd.cap(1).length(), reCmd.cap(1).length() ); + } +} +//END KateCmdLine + +//BEGIN KateIconBorder +using namespace KTextEditor; + +static const char* const plus_xpm[] = { +"11 11 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"...........", +".+++++++++.", +".+++++++++.", +".++++.++++.", +".++++.++++.", +".++.....++.", +".++++.++++.", +".++++.++++.", +".+++++++++.", +".+++++++++.", +"..........."}; + +static const char* const minus_xpm[] = { +"11 11 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"...........", +".+++++++++.", +".+++++++++.", +".+++++++++.", +".+++++++++.", +".++.....++.", +".+++++++++.", +".+++++++++.", +".+++++++++.", +".+++++++++.", +"..........."}; + +static const char * const bookmark_xpm[] = { +"14 13 82 1", +" c None", +". c #F27D01", +"+ c #EF7901", +"@ c #F3940F", +"# c #EE8F12", +"$ c #F9C834", +"% c #F5C33A", +"& c #F09110", +"* c #FCEE3E", +"= c #FBEB3F", +"- c #E68614", +"; c #FA8700", +"> c #F78703", +", c #F4920E", +"' c #F19113", +") c #F6C434", +"! c #FDF938", +"~ c #FDF839", +"{ c #F1BC3A", +"] c #E18017", +"^ c #DA7210", +"/ c #D5680B", +"( c #CA5404", +"_ c #FD8F06", +": c #FCB62D", +"< c #FDE049", +"[ c #FCE340", +"} c #FBE334", +"| c #FDF035", +"1 c #FEF834", +"2 c #FCEF36", +"3 c #F8DF32", +"4 c #F7DC3D", +"5 c #F5CE3E", +"6 c #DE861B", +"7 c #C64C03", +"8 c #F78C07", +"9 c #F8B019", +"0 c #FDE12D", +"a c #FEE528", +"b c #FEE229", +"c c #FBD029", +"d c #E18814", +"e c #CB5605", +"f c #EF8306", +"g c #F3A00E", +"h c #FBC718", +"i c #FED31C", +"j c #FED11D", +"k c #F8B91C", +"l c #E07D0D", +"m c #CB5301", +"n c #ED8A0E", +"o c #F7A90D", +"p c #FEC113", +"q c #FEC013", +"r c #F09B0E", +"s c #D35E03", +"t c #EF9213", +"u c #F9A208", +"v c #FEAA0C", +"w c #FCA10B", +"x c #FCA70B", +"y c #FEAF0B", +"z c #F39609", +"A c #D86203", +"B c #F08C0D", +"C c #FA9004", +"D c #F17F04", +"E c #E36D04", +"F c #E16F03", +"G c #EE8304", +"H c #F88C04", +"I c #DC6202", +"J c #E87204", +"K c #E66A01", +"L c #DC6001", +"M c #D15601", +"N c #DA5D01", +"O c #D25200", +"P c #DA5F00", +"Q c #BC3C00", +" .+ ", +" @# ", +" $% ", +" &*=- ", +" ;>,')!~{]^/( ", +"_:<[}|11234567", +" 890aaaaabcde ", +" fghiiijklm ", +" nopqpqrs ", +" tuvwxyzA ", +" BCDEFGHI ", +" JKL MNO ", +" P Q "}; + +const int iconPaneWidth = 16; +const int halfIPW = 8; + +KateIconBorder::KateIconBorder ( KateViewInternal* internalView, QWidget *parent ) + : QWidget(parent, "", Qt::WStaticContents | Qt::WRepaintNoErase | Qt::WResizeNoErase ) + , m_view( internalView->m_view ) + , m_doc( internalView->m_doc ) + , m_viewInternal( internalView ) + , m_iconBorderOn( false ) + , m_lineNumbersOn( false ) + , m_foldingMarkersOn( false ) + , m_dynWrapIndicatorsOn( false ) + , m_dynWrapIndicators( 0 ) + , m_cachedLNWidth( 0 ) + , m_maxCharWidth( 0 ) +{ + setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) ); + + setBackgroundMode( NoBackground ); + + m_doc->setDescription( MarkInterface::markType01, i18n("Bookmark") ); + m_doc->setPixmap( MarkInterface::markType01, QPixmap((const char**)bookmark_xpm) ); + + updateFont(); +} + +void KateIconBorder::setIconBorderOn( bool enable ) +{ + if( enable == m_iconBorderOn ) + return; + + m_iconBorderOn = enable; + + updateGeometry(); + + QTimer::singleShot( 0, this, SLOT(update()) ); +} + +void KateIconBorder::setLineNumbersOn( bool enable ) +{ + if( enable == m_lineNumbersOn ) + return; + + m_lineNumbersOn = enable; + m_dynWrapIndicatorsOn = (m_dynWrapIndicators == 1) ? enable : m_dynWrapIndicators; + + updateGeometry(); + + QTimer::singleShot( 0, this, SLOT(update()) ); +} + +void KateIconBorder::setDynWrapIndicators( int state ) +{ + if (state == m_dynWrapIndicators ) + return; + + m_dynWrapIndicators = state; + m_dynWrapIndicatorsOn = (state == 1) ? m_lineNumbersOn : state; + + updateGeometry (); + + QTimer::singleShot( 0, this, SLOT(update()) ); +} + +void KateIconBorder::setFoldingMarkersOn( bool enable ) +{ + if( enable == m_foldingMarkersOn ) + return; + + m_foldingMarkersOn = enable; + + updateGeometry(); + + QTimer::singleShot( 0, this, SLOT(update()) ); +} + +QSize KateIconBorder::sizeHint() const +{ + int w = 0; + + if (m_iconBorderOn) + w += iconPaneWidth + 1; + + if (m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn)) { + w += lineNumberWidth(); + } + + if (m_foldingMarkersOn) + w += iconPaneWidth; + + w += 4; + + return QSize( w, 0 ); +} + +// This function (re)calculates the maximum width of any of the digit characters (0 -> 9) +// for graceful handling of variable-width fonts as the linenumber font. +void KateIconBorder::updateFont() +{ + const QFontMetrics *fm = m_view->renderer()->config()->fontMetrics(); + m_maxCharWidth = 0; + // Loop to determine the widest numeric character in the current font. + // 48 is ascii '0' + for (int i = 48; i < 58; i++) { + int charWidth = fm->width( QChar(i) ); + m_maxCharWidth = kMax(m_maxCharWidth, charWidth); + } +} + +int KateIconBorder::lineNumberWidth() const +{ + int width = m_lineNumbersOn ? ((int)log10((double)(m_view->doc()->numLines())) + 1) * m_maxCharWidth + 4 : 0; + + if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) { + width = kMax(style().scrollBarExtent().width() + 4, width); + + if (m_cachedLNWidth != width || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) { + int w = style().scrollBarExtent().width(); + int h = m_view->renderer()->config()->fontMetrics()->height(); + + QSize newSize(w, h); + if ((m_arrow.size() != newSize || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) && !newSize.isEmpty()) { + m_arrow.resize(newSize); + + QPainter p(&m_arrow); + p.fillRect( 0, 0, w, h, m_view->renderer()->config()->iconBarColor() ); + + h = m_view->renderer()->config()->fontMetrics()->ascent(); + + p.setPen(m_view->renderer()->attribute(0)->textColor()); + p.drawLine(w/2, h/2, w/2, 0); +#if 1 + p.lineTo(w/4, h/4); + p.lineTo(0, 0); + p.lineTo(0, h/2); + p.lineTo(w/2, h-1); + p.lineTo(w*3/4, h-1); + p.lineTo(w-1, h*3/4); + p.lineTo(w*3/4, h/2); + p.lineTo(0, h/2); +#else + p.lineTo(w*3/4, h/4); + p.lineTo(w-1,0); + p.lineTo(w-1, h/2); + p.lineTo(w/2, h-1); + p.lineTo(w/4,h-1); + p.lineTo(0, h*3/4); + p.lineTo(w/4, h/2); + p.lineTo(w-1, h/2); +#endif + } + } + } + + return width; +} + +void KateIconBorder::paintEvent(QPaintEvent* e) +{ + paintBorder(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); +} + +void KateIconBorder::paintBorder (int /*x*/, int y, int /*width*/, int height) +{ + static QPixmap minus_px ((const char**)minus_xpm); + static QPixmap plus_px ((const char**)plus_xpm); + + uint h = m_view->renderer()->config()->fontStruct()->fontHeight; + uint startz = (y / h); + uint endz = startz + 1 + (height / h); + uint lineRangesSize = m_viewInternal->lineRanges.size(); + + // center the folding boxes + int m_px = (h - 11) / 2; + if (m_px < 0) + m_px = 0; + + int lnWidth( 0 ); + if ( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) ) // avoid calculating unless needed ;-) + { + lnWidth = lineNumberWidth(); + if ( lnWidth != m_cachedLNWidth || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor() ) + { + // we went from n0 ->n9 lines or vice verca + // this causes an extra updateGeometry() first time the line numbers + // are displayed, but sizeHint() is supposed to be const so we can't set + // the cached value there. + m_cachedLNWidth = lnWidth; + m_oldBackgroundColor = m_view->renderer()->config()->iconBarColor(); + updateGeometry(); + update (); + return; + } + } + + int w( this->width() ); // sane value/calc only once + + QPainter p ( this ); + p.setFont ( *m_view->renderer()->config()->font() ); // for line numbers + // the line number color is for the line numbers, vertical separator lines + // and for for the code folding lines. + p.setPen ( m_view->renderer()->config()->lineNumberColor() ); + + KateLineInfo oldInfo; + if (startz < lineRangesSize) + { + if ((m_viewInternal->lineRanges[startz].line-1) < 0) + oldInfo.topLevel = true; + else + m_doc->lineInfo(&oldInfo,m_viewInternal->lineRanges[startz].line-1); + } + + for (uint z=startz; z <= endz; z++) + { + int y = h * z; + int realLine = -1; + + if (z < lineRangesSize) + realLine = m_viewInternal->lineRanges[z].line; + + int lnX ( 0 ); + + p.fillRect( 0, y, w-4, h, m_view->renderer()->config()->iconBarColor() ); + p.fillRect( w-4, y, 4, h, m_view->renderer()->config()->backgroundColor() ); + + // icon pane + if( m_iconBorderOn ) + { + p.drawLine(lnX+iconPaneWidth, y, lnX+iconPaneWidth, y+h); + + if( (realLine > -1) && (m_viewInternal->lineRanges[z].startCol == 0) ) + { + uint mrk ( m_doc->mark( realLine ) ); // call only once + + if ( mrk ) + { + for( uint bit = 0; bit < 32; bit++ ) + { + MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit); + if( mrk & markType ) + { + QPixmap *px_mark (m_doc->markPixmap( markType )); + + if (px_mark) + { + // center the mark pixmap + int x_px = (iconPaneWidth - px_mark->width()) / 2; + if (x_px < 0) + x_px = 0; + + int y_px = (h - px_mark->height()) / 2; + if (y_px < 0) + y_px = 0; + + p.drawPixmap( lnX+x_px, y+y_px, *px_mark); + } + } + } + } + } + + lnX += iconPaneWidth + 1; + } + + // line number + if( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) ) + { + lnX +=2; + + if (realLine > -1) + if (m_viewInternal->lineRanges[z].startCol == 0) { + if (m_lineNumbersOn) + p.drawText( lnX + 1, y, lnWidth-4, h, Qt::AlignRight|Qt::AlignVCenter, QString("%1").arg( realLine + 1 ) ); + } else if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) { + p.drawPixmap(lnX + lnWidth - m_arrow.width() - 4, y, m_arrow); + } + + lnX += lnWidth; + } + + // folding markers + if( m_foldingMarkersOn ) + { + if( realLine > -1 ) + { + KateLineInfo info; + m_doc->lineInfo(&info,realLine); + + if (!info.topLevel) + { + if (info.startsVisibleBlock && (m_viewInternal->lineRanges[z].startCol == 0)) + { + if (oldInfo.topLevel) + p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1); + else + p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); + + p.drawPixmap(lnX+3,y+m_px,minus_px); + } + else if (info.startsInVisibleBlock) + { + if (m_viewInternal->lineRanges[z].startCol == 0) + { + if (oldInfo.topLevel) + p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1); + else + p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); + + p.drawPixmap(lnX+3,y+m_px,plus_px); + } + else + { + p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); + } + + if (!m_viewInternal->lineRanges[z].wrap) + p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1); + } + else + { + p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); + + if (info.endsBlock && !m_viewInternal->lineRanges[z].wrap) + p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1); + } + } + + oldInfo = info; + } + + lnX += iconPaneWidth; + } + } +} + +KateIconBorder::BorderArea KateIconBorder::positionToArea( const QPoint& p ) const +{ + int x = 0; + if( m_iconBorderOn ) { + x += iconPaneWidth; + if( p.x() <= x ) + return IconBorder; + } + if( m_lineNumbersOn || m_dynWrapIndicators ) { + x += lineNumberWidth(); + if( p.x() <= x ) + return LineNumbers; + } + if( m_foldingMarkersOn ) { + x += iconPaneWidth; + if( p.x() <= x ) + return FoldingMarkers; + } + return None; +} + +void KateIconBorder::mousePressEvent( QMouseEvent* e ) +{ + m_lastClickedLine = m_viewInternal->yToKateLineRange(e->y()).line; + + if ( positionToArea( e->pos() ) != IconBorder ) + { + QMouseEvent forward( QEvent::MouseButtonPress, + QPoint( 0, e->y() ), e->button(), e->state() ); + m_viewInternal->mousePressEvent( &forward ); + } + e->accept(); +} + +void KateIconBorder::mouseMoveEvent( QMouseEvent* e ) +{ + if ( positionToArea( e->pos() ) != IconBorder ) + { + QMouseEvent forward( QEvent::MouseMove, + QPoint( 0, e->y() ), e->button(), e->state() ); + m_viewInternal->mouseMoveEvent( &forward ); + } +} + +void KateIconBorder::mouseReleaseEvent( QMouseEvent* e ) +{ + uint cursorOnLine = m_viewInternal->yToKateLineRange(e->y()).line; + + if (cursorOnLine == m_lastClickedLine && + cursorOnLine <= m_doc->lastLine() ) + { + BorderArea area = positionToArea( e->pos() ); + if( area == IconBorder) { + if (e->button() == LeftButton) { + if( m_doc->editableMarks() & KateViewConfig::global()->defaultMarkType() ) { + if( m_doc->mark( cursorOnLine ) & KateViewConfig::global()->defaultMarkType() ) + m_doc->removeMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() ); + else + m_doc->addMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() ); + } else { + showMarkMenu( cursorOnLine, QCursor::pos() ); + } + } + else + if (e->button() == RightButton) { + showMarkMenu( cursorOnLine, QCursor::pos() ); + } + } + + if ( area == FoldingMarkers) { + KateLineInfo info; + m_doc->lineInfo(&info,cursorOnLine); + if ((info.startsVisibleBlock) || (info.startsInVisibleBlock)) { + emit toggleRegionVisibility(cursorOnLine); + } + } + } + + QMouseEvent forward( QEvent::MouseButtonRelease, + QPoint( 0, e->y() ), e->button(), e->state() ); + m_viewInternal->mouseReleaseEvent( &forward ); +} + +void KateIconBorder::mouseDoubleClickEvent( QMouseEvent* e ) +{ + QMouseEvent forward( QEvent::MouseButtonDblClick, + QPoint( 0, e->y() ), e->button(), e->state() ); + m_viewInternal->mouseDoubleClickEvent( &forward ); +} + +void KateIconBorder::showMarkMenu( uint line, const QPoint& pos ) +{ + QPopupMenu markMenu; + QPopupMenu selectDefaultMark; + + typedef QValueVector<int> MarkTypeVector; + MarkTypeVector vec( 33 ); + int i=1; + + for( uint bit = 0; bit < 32; bit++ ) { + MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit); + if( !(m_doc->editableMarks() & markType) ) + continue; + + if( !m_doc->markDescription( markType ).isEmpty() ) { + markMenu.insertItem( m_doc->markDescription( markType ), i ); + selectDefaultMark.insertItem( m_doc->markDescription( markType ), i+100); + } else { + markMenu.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i ); + selectDefaultMark.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i+100); + } + + if( m_doc->mark( line ) & markType ) + markMenu.setItemChecked( i, true ); + + if( markType & KateViewConfig::global()->defaultMarkType() ) + selectDefaultMark.setItemChecked( i+100, true ); + + vec[i++] = markType; + } + + if( markMenu.count() == 0 ) + return; + + if( markMenu.count() > 1 ) + markMenu.insertItem( i18n("Set Default Mark Type" ), &selectDefaultMark); + + int result = markMenu.exec( pos ); + if( result <= 0 ) + return; + + if ( result > 100) + { + KateViewConfig::global()->setDefaultMarkType (vec[result-100]); + // flush config, otherwise it isn't nessecarily done + KConfig *config = kapp->config(); + config->setGroup("Kate View Defaults"); + KateViewConfig::global()->writeConfig( config ); + } + else + { + MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes) vec[result]; + if( m_doc->mark( line ) & markType ) { + m_doc->removeMark( line, markType ); + } else { + m_doc->addMark( line, markType ); + } + } +} +//END KateIconBorder + +KateViewEncodingAction::KateViewEncodingAction(KateDocument *_doc, KateView *_view, const QString& text, QObject* parent, const char* name) + : KActionMenu (text, parent, name), doc(_doc), view (_view) +{ + connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow())); +} + +void KateViewEncodingAction::slotAboutToShow() +{ + QStringList modes (KGlobal::charsets()->descriptiveEncodingNames()); + + popupMenu()->clear (); + for (uint z=0; z<modes.size(); ++z) + { + popupMenu()->insertItem ( modes[z], this, SLOT(setMode(int)), 0, z); + + bool found = false; + QTextCodec *codecForEnc = KGlobal::charsets()->codecForName(KGlobal::charsets()->encodingForName(modes[z]), found); + + if (found && codecForEnc) + { + if (codecForEnc->name() == doc->config()->codec()->name()) + popupMenu()->setItemChecked (z, true); + } + } +} + +void KateViewEncodingAction::setMode (int mode) +{ + QStringList modes (KGlobal::charsets()->descriptiveEncodingNames()); + doc->config()->setEncoding( KGlobal::charsets()->encodingForName( modes[mode] ) ); + // now we don't want the encoding changed again unless the user does so using the menu. + doc->setEncodingSticky( true ); + doc->reloadFile(); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; |