/*************************************************************************** * Copyright (C) 2005 by David Saxton * * david@bluehaze.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #define protected public #include #undef protected #include "asmformatter.h" #include "filemetainfo.h" #include "gpsimprocessor.h" #include "ktechlab.h" #include "symbolviewer.h" #include "textdocument.h" #include "textview.h" #include "variablelabel.h" #include "viewiface.h" #include #include // #include "kateview.h" #include #include #include #include #include #include #include #include #include //BEGIN class TextView TextView::TextView( TextDocument * textDocument, ViewContainer *viewContainer, uint viewAreaId, const char *name ) : View( textDocument, viewContainer, viewAreaId, name ) { m_view = textDocument->createKateView(this); m_view->insertChildClient(this); TDEActionCollection * ac = actionCollection(); //BEGIN Convert To * Actions TDEToolBarPopupAction * pa = new TDEToolBarPopupAction( i18n("Convert to"), "fork", 0, 0, 0, ac, "program_convert" ); pa->setDelayed(false); TDEPopupMenu * m = pa->popupMenu(); m->insertTitle( i18n("Convert to ...") ); m->insertItem( TDEGlobal::iconLoader()->loadIcon( "convert_to_microbe", TDEIcon::Small ), i18n("Microbe"), TextDocument::MicrobeOutput ); m->insertItem( TDEGlobal::iconLoader()->loadIcon( "convert_to_assembly", TDEIcon::Small ), i18n("Assembly"), TextDocument::AssemblyOutput ); m->insertItem( TDEGlobal::iconLoader()->loadIcon( "convert_to_hex", TDEIcon::Small ), i18n("Hex"), TextDocument::HexOutput ); m->insertItem( TDEGlobal::iconLoader()->loadIcon( "convert_to_pic", TDEIcon::Small ), i18n("PIC (upload)"), TextDocument::PICOutput ); connect( m, TQT_SIGNAL(activated(int)), textDocument, TQT_SLOT(slotConvertTo(int)) ); m->setItemEnabled( TextDocument::MicrobeOutput, false ); //END Convert To * Actions new TDEAction( i18n("Format Assembly Code"), "", TQt::Key_F12, textDocument, TQT_SLOT(formatAssembly()), ac, "format_asm" ); #ifndef NO_GPSIM //BEGIN Debug Actions new TDEAction( i18n("Set &Breakpoint"), 0, 0, TQT_TQOBJECT(this), TQT_SLOT(toggleBreakpoint()), ac, "debug_toggle_breakpoint" ); new TDEAction( i18n("Run"), "dbgrun", 0, textDocument, TQT_SLOT(debugRun()), ac, "debug_run" ); new TDEAction( i18n("Interrupt"), "media-playback-pause", 0, textDocument, TQT_SLOT(debugInterrupt()), ac, "debug_interrupt" ); new TDEAction( i18n("Stop"), "process-stop", 0, textDocument, TQT_SLOT(debugStop()), ac, "debug_stop" ); new TDEAction( i18n("Step"), "dbgstep", TQt::CTRL|TQt::ALT|TQt::Key_Right, textDocument, TQT_SLOT(debugStep()), ac, "debug_step" ); new TDEAction( i18n("Step Over"), "dbgnext", 0, textDocument, TQT_SLOT(debugStepOver()), ac, "debug_step_over" ); new TDEAction( i18n("Step Out"), "dbgstepout", 0, textDocument, TQT_SLOT(debugStepOut()), ac, "debug_step_out" ); //END Debug Actions #endif setXMLFile( "ktechlabtextui.rc" ); m_view->setXMLFile( locate( "appdata", "ktechlabkateui.rc" ) ); m_savedCursorLine = 0; m_savedCursorColumn = 0; m_pViewIface = new TextViewIface(this); setAcceptDrops(true); m_statusBar->insertItem( "", ViewStatusBar::LineCol ); m_view->installPopup( static_cast( p_ktechlab->factory()->container( "tdetexteditor_popup", p_ktechlab ) ) ); connect( m_view, TQT_SIGNAL(cursorPositionChanged()), this, TQT_SLOT(slotCursorPositionChanged()) ); connect( m_view, TQT_SIGNAL(gotFocus(Kate::View*)), this, TQT_SLOT(setFocused()) ); m_layout->insertWidget( 0, m_view ); slotCursorPositionChanged(); slotInitDebugActions(); initCodeActions(); #ifndef NO_GPSIM m_pTextViewLabel = new VariableLabel( this ); m_pTextViewLabel->hide(); TextViewEventFilter * eventFilter = new TextViewEventFilter( this ); connect( eventFilter, TQT_SIGNAL(wordHoveredOver( const TQString&, int, int )), this, TQT_SLOT(slotWordHoveredOver( const TQString&, int, int )) ); connect( eventFilter, TQT_SIGNAL(wordUnhovered()), this, TQT_SLOT(slotWordUnhovered()) ); TQObject * internalView = m_view->child( 0, "KateViewInternal" ); internalView->installEventFilter( eventFilter ); #endif } TextView::~TextView() { if ( p_ktechlab ) { if ( KXMLGUIFactory * f = m_view->factory() ) f->removeClient( m_view ); p_ktechlab->addNoRemoveGUIClient( m_view ); } delete m_pViewIface; m_pViewIface = 0l; } bool TextView::closeView() { if ( textDocument() ) { const TQString path = textDocument()->url().prettyURL(); if ( !path.isEmpty() ) fileMetaInfo()->grabMetaInfo( path, this ); } bool doClose = View::closeView(); if (doClose) p_ktechlab->factory()->removeClient(m_view); return View::closeView(); } TextDocument *TextView::textDocument() const { return static_cast(document()); } void TextView::disableActions() { TDEPopupMenu * tb = (dynamic_cast(action("program_convert")))->popupMenu(); tb->setItemEnabled( TextDocument::AssemblyOutput, false ); tb->setItemEnabled( TextDocument::HexOutput, false ); tb->setItemEnabled( TextDocument::PICOutput, false ); action("format_asm")->setEnabled(false); #ifndef NO_GPSIM action("debug_toggle_breakpoint")->setEnabled(false); #endif } void TextView::setFocused() { View::setFocused(); #ifndef NO_GPSIM GpsimDebugger * debugger = textDocument()->debugger(); if ( !debugger || !debugger->gpsim() ) return; SymbolViewer::self()->setContext( debugger->gpsim() ); #endif } void TextView::initCodeActions() { disableActions(); TDEPopupMenu * tb = (dynamic_cast(action("program_convert")))->popupMenu(); switch ( textDocument()->guessedCodeType() ) { case TextDocument::ct_asm: { tb->setItemEnabled( TextDocument::HexOutput, true ); tb->setItemEnabled( TextDocument::PICOutput, true ); action("format_asm")->setEnabled(true); #ifndef NO_GPSIM action("debug_toggle_breakpoint")->setEnabled(true); slotInitDebugActions(); #endif break; } case TextDocument::ct_c: { tb->setItemEnabled( TextDocument::AssemblyOutput, true ); tb->setItemEnabled( TextDocument::HexOutput, true ); tb->setItemEnabled( TextDocument::PICOutput, true ); break; } case TextDocument::ct_hex: { tb->setItemEnabled( TextDocument::AssemblyOutput, true ); tb->setItemEnabled( TextDocument::PICOutput, true ); break; } case TextDocument::ct_microbe: { tb->setItemEnabled( TextDocument::AssemblyOutput, true ); tb->setItemEnabled( TextDocument::HexOutput, true ); tb->setItemEnabled( TextDocument::PICOutput, true ); break; } case TextDocument::ct_unknown: { break; } } } unsigned TextView::currentLine() { unsigned l,c ; m_view->cursorPosition( &l, &c ); return l; } unsigned TextView::currentColumn() { unsigned l,c ; m_view->cursorPosition( &l, &c ); return c; } void TextView::saveCursorPosition() { m_view->cursorPosition( &m_savedCursorLine, &m_savedCursorColumn ); } void TextView::restoreCursorPosition() { m_view->setCursorPosition( m_savedCursorLine, m_savedCursorColumn ); } void TextView::slotCursorPositionChanged() { uint line, column; m_view->cursorPosition( &line, &column ); m_statusBar->changeItem( i18n(" Line: %1 Col: %2 ").arg(TQString::number(line+1)).arg(TQString::number(column+1)), ViewStatusBar::LineCol ); slotUpdateMarksInfo(); } void TextView::slotUpdateMarksInfo() { #ifndef NO_GPSIM uint l,c ; m_view->cursorPosition( &l, &c ); if ( m_view->getDoc()->mark(l) & TextDocument::Breakpoint ) action("debug_toggle_breakpoint")->setText( i18n("Clear &Breakpoint") ); else action("debug_toggle_breakpoint")->setText( i18n("Set &Breakpoint") ); #endif } void TextView::slotInitDebugActions() { #ifndef NO_GPSIM bool isRunning = textDocument()->debuggerIsRunning(); bool isStepping = textDocument()->debuggerIsStepping(); bool ownDebugger = textDocument()->ownDebugger(); action("debug_run")->setEnabled( !isRunning || isStepping ); action("debug_interrupt")->setEnabled(isRunning && !isStepping); action("debug_stop")->setEnabled(isRunning && ownDebugger); action("debug_step")->setEnabled(isRunning && isStepping); action("debug_step_over")->setEnabled(isRunning && isStepping); action("debug_step_out")->setEnabled(isRunning && isStepping); #endif // !NO_GPSIM } void TextView::toggleBreakpoint() { #ifndef NO_GPSIM uint l,c ; m_view->cursorPosition( &l, &c ); textDocument()->setBreakpoint( l, !(m_view->getDoc()->mark(l) & TextDocument::Breakpoint) ); #endif // !NO_GPSIM } void TextView::slotWordHoveredOver( const TQString & word, int line, int col ) { #ifndef NO_GPSIM // We're only interested in popping something up if we currently have a debugger running GpsimProcessor * gpsim = textDocument()->debugger() ? textDocument()->debugger()->gpsim() : 0l; if ( !gpsim ) { m_pTextViewLabel->hide(); return; } // Find out if the word that we are hovering over is the operand data KTextEditor::EditInterface * e = (KTextEditor::EditInterface*)textDocument()->kateDocument()->tqt_cast("KTextEditor::EditInterface"); InstructionParts parts( e->textLine( unsigned(line) ) ); if ( !parts.operandData().contains( word ) ) return; if ( RegisterInfo * info = gpsim->registerMemory()->fromName( word ) ) m_pTextViewLabel->setRegister( info, info->name() ); else { int operandAddress = textDocument()->debugger()->programAddress( textDocument()->debugFile(), line ); if ( operandAddress == -1 ) { m_pTextViewLabel->hide(); return; } int regAddress = gpsim->operandRegister( operandAddress ); if ( regAddress != -1 ) m_pTextViewLabel->setRegister( gpsim->registerMemory()->fromAddress( regAddress ), word ); else { m_pTextViewLabel->hide(); return; } } m_pTextViewLabel->move( mapFromGlobal( TQCursor::pos() ) + TQPoint( 0, 20 ) ); m_pTextViewLabel->show(); #endif // !NO_GPSIM } void TextView::slotWordUnhovered() { #ifndef NO_GPSIM m_pTextViewLabel->hide(); #endif // !NO_GPSIM } //END class TextView //BEGIN class TextViewEventFilter TextViewEventFilter::TextViewEventFilter( TextView * textView ) { m_hoverStatus = Sleeping; m_pTextView = textView; m_lastLine = m_lastCol = -1; ((KTextEditor::TextHintInterface*)textView->kateView()->tqt_cast("KTextEditor::TextHintInterface"))->enableTextHints(0); connect( textView->kateView(), TQT_SIGNAL(needTextHint(int, int, TQString &)), this, TQT_SLOT(slotNeedTextHint( int, int, TQString& )) ); m_pHoverTimer = new TQTimer( this ); connect( m_pHoverTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(hoverTimeout()) ); m_pSleepTimer = new TQTimer( this ); connect( m_pSleepTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(gotoSleep()) ); m_pNoWordTimer = new TQTimer( this ); connect( m_pNoWordTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotNoWordTimeout()) ); } bool TextViewEventFilter::eventFilter( TQObject *, TQEvent * e ) { if ( e->type() == TQEvent::MouseMove ) { if ( !m_pNoWordTimer->isActive() ) m_pNoWordTimer->start( 10 ); return false; } if ( e->type() == TQEvent::FocusOut || e->type() == TQEvent::FocusIn || e->type() == TQEvent::MouseButtonPress || e->type() == TQEvent::Leave || e->type() == TQEvent::Wheel ) { // user moved focus somewhere - hide the tip and sleep if ( ((TQFocusEvent*)e)->reason() != TQFocusEvent::Popup ) updateHovering( 0, -1, -1 ); } return false; } void TextViewEventFilter::hoverTimeout() { m_pSleepTimer->stop(); m_hoverStatus = Active; emit wordHoveredOver( m_lastWord, m_lastLine, m_lastCol ); } void TextViewEventFilter::gotoSleep() { m_hoverStatus = Sleeping; m_lastWord = TQString(); emit wordUnhovered(); m_pHoverTimer->stop(); } void TextViewEventFilter::slotNoWordTimeout() { updateHovering( 0, -1, -1 ); } void TextViewEventFilter::updateHovering( const TQString & currentWord, int line, int col ) { if ( (currentWord == m_lastWord) && (line == m_lastLine) ) return; m_lastWord = currentWord; m_lastLine = line; m_lastCol = col; if ( currentWord.isEmpty() ) { if ( m_hoverStatus == Active ) m_hoverStatus = Hidden; emit wordUnhovered(); if ( !m_pSleepTimer->isActive() ) m_pSleepTimer->start( 2000, true ); return; } if ( m_hoverStatus != Sleeping ) emit wordHoveredOver( currentWord, line, col ); else m_pHoverTimer->start( 700, true ); } static inline bool isWordLetter( const TQString & s ) { return (s.length() == 1) && (s[0].isLetterOrNumber() || s[0] == '_'); } void TextViewEventFilter::slotNeedTextHint( int line, int col, TQString & ) { m_pNoWordTimer->stop(); KTextEditor::EditInterface * e = (KTextEditor::EditInterface*)m_pTextView->textDocument()->kateDocument()->tqt_cast("KTextEditor::EditInterface"); // Return if we aren't currently in a word if ( !isWordLetter( e->text( line, col, line, col+1 ) ) ) { updateHovering( TQString(), line, col ); return; } // Find the start of the word int wordStart = col; do wordStart--; while ( wordStart > 0 && isWordLetter( e->text( line, wordStart, line, wordStart+1 ) ) ); wordStart++; // Find the end of the word int wordEnd = col; do wordEnd++; while ( isWordLetter( e->text( line, wordEnd, line, wordEnd+1 ) ) ); TQString t = e->text( line, wordStart, line, wordEnd ); updateHovering( t, line, col ); } //END class TextViewEventFilter #include "textview.moc"