summaryrefslogtreecommitdiffstats
path: root/languages/lib/debugger/debugger.cpp
blob: 92765efe788b67e0c94236dd00845c21dd98602c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

#include "debugger.h"

#include <kdebug.h>
#include <klocale.h>
#include <ktexteditor/document.h>

// #include "editorproxy.h"
#include <kdevpartcontroller.h>


using namespace KTextEditor;

Debugger *Debugger::s_instance = 0;

Debugger::Debugger(KDevPartController *partController)
    :m_partController(partController)
{
    connect( m_partController, SIGNAL(partAdded(KParts::Part*)),
             this, SLOT(partAdded(KParts::Part*)) );
}


Debugger::~Debugger()
{}


// Debugger *Debugger::getInstance()
// {
//     if (!s_instance)
//         s_instance = new Debugger;
//
//     return s_instance;
// }


void Debugger::setBreakpoint(const QString &fileName, int lineNum, int id, bool enabled, bool pending)
{
    KParts::Part *part = m_partController->partForURL(KURL(fileName));
    if( !part )
        return;

    MarkInterface *iface = dynamic_cast<MarkInterface*>(part);
    if (!iface)
        return;

    // Temporarily disconnect so we don't get confused by receiving extra
    // marksChanged signals
    disconnect( part, SIGNAL(marksChanged()), this, SLOT(marksChanged()) );
    iface->removeMark( lineNum, Breakpoint | ActiveBreakpoint | ReachedBreakpoint | DisabledBreakpoint );

    BPItem bpItem(fileName, lineNum);
    QValueList<BPItem>::Iterator it = BPList.find(bpItem);
    if (it != BPList.end())
    {
//        kdDebug(9012) << "Removing BP=" << fileName << ":" << lineNum << endl;
        BPList.remove(it);
    }

    // An id of -1 means this breakpoint should be hidden from the user.
    // I believe this functionality is not used presently.
    if( id != -1 )
    {
        uint markType = Breakpoint;
        if( !pending )
            markType |= ActiveBreakpoint;
        if( !enabled )
            markType |= DisabledBreakpoint;
        iface->addMark( lineNum, markType );
//        kdDebug(9012) << "Appending BP=" << fileName << ":" << lineNum << endl;
        BPList.append(BPItem(fileName, lineNum));
    }

    connect( part, SIGNAL(marksChanged()), this, SLOT(marksChanged()) );
}


void Debugger::clearExecutionPoint()
{
    QPtrListIterator<KParts::Part> it(*m_partController->parts());
    for ( ; it.current(); ++it)
    {
        MarkInterface *iface = dynamic_cast<MarkInterface*>(it.current());
        if (!iface)
            continue;

        QPtrList<Mark> list = iface->marks();
        QPtrListIterator<Mark> markIt(list);
        for( ; markIt.current(); ++markIt )
        {
            Mark* mark = markIt.current();
            if( mark->type & ExecutionPoint )
                iface->removeMark( mark->line, ExecutionPoint );
        }
    }
}


void Debugger::gotoExecutionPoint(const KURL &url, int lineNum)
{
    clearExecutionPoint();

    m_partController->editDocument(url, lineNum);

    KParts::Part *part = m_partController->partForURL(url);
    if( !part )
        return;
    MarkInterface *iface = dynamic_cast<MarkInterface*>(part);
    if( !iface )
        return;

    iface->addMark( lineNum, ExecutionPoint );
}

void Debugger::marksChanged()
{
    if(sender()->inherits("KTextEditor::Document") )
    {
        KTextEditor::Document* doc = (KTextEditor::Document*) sender();
        MarkInterface* iface = KTextEditor::markInterface( doc );

        if (iface)
        {
            if( !m_partController->partForURL( doc->url() ) )
                return; // Probably means the document is being closed.

            KTextEditor::Mark *m;
            QValueList<BPItem> oldBPList = BPList;
            QPtrList<KTextEditor::Mark> newMarks = iface->marks();

            // Compare the oldBPlist to the new list from the editor.
            //
            // If we don't have some of the old breakpoints in the new list
            // then they have been moved by the user adding or removing source
            // code. Remove these old breakpoints
            //
            // If we _can_ find these old breakpoints in the newlist then
            // nothing has happened to them. We can just ignore these and to
            // do that we must remove them from the new list.

            bool bpchanged = false;

            for (uint i = 0; i < oldBPList.count(); i++)
            {
                if (oldBPList[i].fileName() != doc->url().path())
                    continue;

                bool found=false;
                for (uint newIdx=0; newIdx < newMarks.count(); newIdx++)
                {
                    m = newMarks.at(newIdx);
                    if ((m->type & Breakpoint) &&
                            m->line == oldBPList[i].lineNum() &&
                            doc->url().path() == oldBPList[i].fileName())
                    {
                        newMarks.remove(newIdx);
                        found=true;
                        break;
                    }
                }

                if (!found)
                {
                    emit toggledBreakpoint( doc->url().path(), oldBPList[i].lineNum() );
                    bpchanged = true;
                }
            }

            // Any breakpoints left in the new list are the _new_ position of
            // the moved breakpoints. So add these as new breakpoints via
            // toggling them.
            for (uint i = 0; i < newMarks.count(); i++)
            {
                m = newMarks.at(i);
                if (m->type & Breakpoint)
                {
                    emit toggledBreakpoint( doc->url().path(), m->line );
                    bpchanged = true;
                }
            }

            if ( bpchanged && m_partController->activePart() == doc )
            {
                //bring focus back to the editor
                m_partController->activatePart( doc );
            }
        }
    }
}


void Debugger::partAdded( KParts::Part* part )
{
    MarkInterfaceExtension *iface = dynamic_cast<MarkInterfaceExtension*>(part);
    if( !iface )
        return;

    iface->setDescription((MarkInterface::MarkTypes)Breakpoint, i18n("Breakpoint"));
    iface->setPixmap((MarkInterface::MarkTypes)Breakpoint, *inactiveBreakpointPixmap());
    iface->setPixmap((MarkInterface::MarkTypes)ActiveBreakpoint, *activeBreakpointPixmap());
    iface->setPixmap((MarkInterface::MarkTypes)ReachedBreakpoint, *reachedBreakpointPixmap());
    iface->setPixmap((MarkInterface::MarkTypes)DisabledBreakpoint, *disabledBreakpointPixmap());
    iface->setPixmap((MarkInterface::MarkTypes)ExecutionPoint, *executionPointPixmap());
    iface->setMarksUserChangable( Bookmark | Breakpoint );

    connect( part, SIGNAL(marksChanged()), this, SLOT(marksChanged()) );
}

#include "debugger.moc"