KHtml

debugdocument.cpp
1 #include "debugdocument.h"
2 #include "debugwindow.h"
3 
4 #include <QApplication>
5 
6 #include "kjs_binding.h"
7 #include "khtml_part.h"
8 
9 #include <ktexteditor/document.h>
10 #include <ktexteditor/view.h>
11 #include <ktexteditor/editor.h>
12 #include <ktexteditor/configinterface.h>
13 #include <ktexteditor/markinterface.h>
14 #include <kiconloader.h>
15 #include <kmessagebox.h>
16 #include <qcryptographichash.h>
17 
18 using namespace KJS;
19 using namespace KJSDebugger;
20 
21 DebugDocument::DebugDocument(KJS::Interpreter *intp, const QString &url,
22  int sourceId, int baseLine, const QString &source)
23 {
24  m_interpreter = intp;
25  m_url = url;
26 
27  m_firstLine = baseLine;
28  m_sourceId = sourceId;
29  m_sourceLines = source.split('\n');
30 
31  QUrl kurl(url);
32  m_name = kurl.fileName();
33 
34  // Might have to fall back in case of query-like things;
35  // ad scripts tend to do that
36  while (m_name.contains("=") || m_name.contains("&")) {
37  kurl = kurl.upUrl();
38  m_name = kurl.fileName();
39  }
40 
41  if (m_name.isEmpty()) {
42  m_name = kurl.host();
43  }
44 
45  if (m_name.isEmpty()) {
46  m_name = "????"; //Probably better than un-i18n'd 'undefined'...
47  }
48 
49  m_kteDoc = 0;
50  m_kteView = 0;
51  m_rebuilding = false;
52  m_reload = false;
53  m_hasFunctions = false;
54 }
55 
56 DebugDocument::~DebugDocument()
57 {
58  emit documentDestroyed(this);
59 
60  // View has an another parent for UI purposes, so we have to clean it up
61  delete m_kteView;
62 }
63 
64 KJS::Interpreter *DebugDocument::interpreter()
65 {
66  return m_interpreter;
67 }
68 
69 bool DebugDocument::hasFunctions()
70 {
71  return m_hasFunctions;
72 }
73 
74 void DebugDocument::setHasFunctions()
75 {
76  m_hasFunctions = true;
77 }
78 
79 QString DebugDocument::name() const
80 {
81  return m_name;
82 }
83 
84 int DebugDocument::sid() const
85 {
86  return m_sourceId;
87 }
88 
89 int DebugDocument::baseLine() const
90 {
91  return m_firstLine;
92 }
93 
94 int DebugDocument::length() const
95 {
96  return m_sourceLines.size();
97 }
98 
99 QString DebugDocument::url() const
100 {
101  return m_url;
102 }
103 
104 void DebugDocument::reloaded(int sourceId, const QString &source)
105 {
106  assert(m_reload);
107  m_reload = false;
108 
109  m_sourceLines = source.split('\n');
110  m_sourceId = sourceId;
111  m_md5.clear();
112 
113  if (m_kteDoc) { // Update docu if needed
114  rebuildViewerDocument();
115  }
116 }
117 
118 void DebugDocument::markReload()
119 {
120  m_reload = true;
121 }
122 
123 bool DebugDocument::isMarkedReload() const
124 {
125  return m_reload;
126 }
127 
128 void DebugDocument::setBreakpoint(int lineNumber)
129 {
130  if (m_rebuilding) {
131  return;
132  }
133 
134  breakpoints().append(lineNumber);
135 }
136 
137 void DebugDocument::removeBreakpoint(int lineNumber)
138 {
139  if (m_rebuilding) {
140  return;
141  }
142 
143  QVector<int> &br = breakpoints();
144  int idx = breakpoints().indexOf(lineNumber);
145  if (idx != -1) {
146  br.remove(idx);
147  if (br.isEmpty() && !m_url.isEmpty()) {
148  // We just removed the last breakpoint per URL,
149  // so we can kill the entire list
150  s_perUrlBreakPoints->remove(url());
151  }
152  }
153 }
154 
155 bool DebugDocument::hasBreakpoint(int lineNumber)
156 {
157  return breakpoints().contains(lineNumber);
158 }
159 
160 QHash<QString, QVector<int> > *DebugDocument::s_perUrlBreakPoints = 0;
161 QHash<QString, QVector<int> > *DebugDocument::s_perHashBreakPoints = 0;
162 
163 QVector<int> &DebugDocument::breakpoints()
164 {
165  if (m_url.isEmpty()) {
166  if (!s_perHashBreakPoints) {
167  s_perHashBreakPoints = new QHash<QString, QVector<int> >;
168  }
169 
170  if (m_md5.isEmpty()) {
172  hash.addData(m_sourceLines.join("\n").toUtf8());
173  m_md5 = QString::fromLatin1(hash.result().toHex());
174  }
175 
176  return (*s_perHashBreakPoints)[m_md5];
177  } else {
178  if (!s_perUrlBreakPoints) {
179  s_perUrlBreakPoints = new QHash<QString, QVector<int> >;
180  }
181 
182  return (*s_perUrlBreakPoints)[m_url];
183  }
184 }
185 
186 KTextEditor::Document *DebugDocument::viewerDocument()
187 {
188  if (!m_kteDoc) {
189  rebuildViewerDocument();
190  }
191  return m_kteDoc;
192 }
193 
194 KTextEditor::Editor *DebugDocument::s_kate = 0;
195 
196 KTextEditor::Editor *DebugDocument::kate()
197 {
198  if (!s_kate) {
199  s_kate = KTextEditor::editor("katepart");
200  }
201 
202  if (!s_kate) {
203  KMessageBox::error(DebugWindow::window(), i18n("Unable to find the Kate editor component;\n"
204  "please check your KDE installation."));
205  qApp->exit(1);
206  }
207 
208  return s_kate;
209 }
210 
211 void DebugDocument::rebuildViewerDocument()
212 {
213  m_rebuilding = true;
214 
215  if (!m_kteDoc) {
216  m_kteDoc = kate()->createDocument(this);
217  setupViewerDocument();
218  }
219 
220  KTextEditor::Cursor oldPos;
221  if (m_kteView) {
222  oldPos = m_kteView->cursorPosition();
223  }
224 
225  m_kteDoc->setReadWrite(true);
226  m_kteDoc->setText(m_sourceLines.join("\n"));
227 
228  // Restore cursor pos, if there is a view
229  if (m_kteView) {
230  m_kteView->setCursorPosition(oldPos);
231  }
232 
233  // Check off the pending/URL-based breakpoints. We have to do even
234  // when the document is being updated as they may be on later lines
235  // Note that we have to fiddle with them based on our base line, as
236  // views will always start at 0, even for later fragments
237  KTextEditor::MarkInterface *imark = qobject_cast<KTextEditor::MarkInterface *>(m_kteDoc);
238  if (imark) {
239  QVector<int> &bps = breakpoints();
240  foreach (int bpLine, bps) {
241  int relLine = bpLine - m_firstLine;
242  if (0 <= relLine && relLine < length()) {
243  imark->addMark(relLine, KTextEditor::MarkInterface::BreakpointActive);
244  }
245  }
246  }
247 
248  m_kteDoc->setReadWrite(false);
249  m_rebuilding = false;
250 }
251 
252 void DebugDocument::setupViewerDocument()
253 {
254  // Highlight as JS..
255  m_kteDoc->setMode("JavaScript");
256 
257  // Configure all the breakpoint/execution point marker stuff.
258  // ### there is an odd split of mark use between here and DebugWindow.
259  // Perhaps we should just emit a single and let it do it, and
260  // limit ourselves to ownership?
261  KTextEditor::MarkInterface *imark = qobject_cast<KTextEditor::MarkInterface *>(m_kteDoc);
262  assert(imark);
263 
264  imark->setEditableMarks(KTextEditor::MarkInterface::BreakpointActive);
267 
268  imark->setMarkDescription(KTextEditor::MarkInterface::BreakpointActive,
269  i18n("Breakpoint"));
270  imark->setMarkPixmap(KTextEditor::MarkInterface::BreakpointActive,
271  SmallIcon("flag-red"));
272  imark->setMarkPixmap(KTextEditor::MarkInterface::Execution,
273  SmallIcon("arrow-right"));
274 }
275 
276 KTextEditor::View *DebugDocument::viewerView()
277 {
278  if (m_kteView) {
279  return m_kteView;
280  }
281 
282  // Ensure document is created
283  viewerDocument();
284 
285  m_kteView = m_kteDoc->createView(DebugWindow::window());
286  KTextEditor::ConfigInterface *iconf = qobject_cast<KTextEditor::ConfigInterface *>(m_kteView);
287  assert(iconf);
288  if (iconf->configKeys().contains("line-numbers")) {
289  iconf->setConfigValue("line-numbers", false);
290  }
291  if (iconf->configKeys().contains("icon-bar")) {
292  iconf->setConfigValue("icon-bar", true);
293  }
294  if (iconf->configKeys().contains("dynamic-word-wrap")) {
295  iconf->setConfigValue("dynamic-word-wrap", true);
296  }
297 
298  return m_kteView;
299 }
300 
virtual void setConfigValue(const QString &key, const QVariant &value)=0
void clear()
virtual void setMarkPixmap(MarkTypes mark, const QPixmap &pixmap)=0
virtual void setMarkDescription(MarkTypes mark, const QString &text)=0
int size() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void remove(int i)
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
virtual void setEditableMarks(uint markMask)=0
QString i18n(const char *text, const TYPE &arg...)
bool isEmpty() const const
virtual void addMark(int line, uint markType)=0
QString fromLatin1(const char *str, int size)
virtual QStringList configKeys() const =0
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:47:59 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.