]> git.saurik.com Git - wxWidgets.git/blame - src/html/htmlwin.cpp
added wxTextCtrl::HitTest(); implemented it for MSW
[wxWidgets.git] / src / html / htmlwin.cpp
CommitLineData
5526e819
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: htmlwin.cpp
3// Purpose: wxHtmlWindow class for parsing & displaying HTML (implementation)
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
5526e819
VS
6// Copyright: (c) 1999 Vaclav Slavik
7// Licence: wxWindows Licence
8/////////////////////////////////////////////////////////////////////////////
9
10
14f355c2 11#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
892aeafc
VS
12#pragma implementation "htmlwin.h"
13#pragma implementation "htmlproc.h"
5526e819
VS
14#endif
15
3096bd2f 16#include "wx/wxprec.h"
5526e819
VS
17
18#include "wx/defs.h"
f6bcfd97 19#if wxUSE_HTML && wxUSE_STREAMS
5526e819 20
2b5f62a0 21#ifdef __BORLANDC__
5526e819
VS
22#pragma hdrstop
23#endif
24
25#ifndef WXPRECOMP
04dbb646
VZ
26 #include "wx/log.h"
27 #include "wx/intl.h"
28 #include "wx/dcclient.h"
29 #include "wx/frame.h"
5526e819
VS
30#endif
31
69941f05 32#include "wx/html/htmlwin.h"
892aeafc 33#include "wx/html/htmlproc.h"
892aeafc 34#include "wx/list.h"
e3774124 35#include "wx/clipbrd.h"
2b2309a4 36#include "wx/dataobj.h"
1338c59a
VS
37#include "wx/timer.h"
38#include "wx/dcmemory.h"
04dbb646
VZ
39
40#include "wx/arrimpl.cpp"
892aeafc
VS
41#include "wx/listimpl.cpp"
42
1338c59a
VS
43
44
45#if wxUSE_CLIPBOARD
46// ----------------------------------------------------------------------------
47// wxHtmlWinAutoScrollTimer: the timer used to generate a stream of scroll
48// events when a captured mouse is held outside the window
49// ----------------------------------------------------------------------------
50
51class wxHtmlWinAutoScrollTimer : public wxTimer
52{
53public:
54 wxHtmlWinAutoScrollTimer(wxScrolledWindow *win,
55 wxEventType eventTypeToSend,
56 int pos, int orient)
57 {
58 m_win = win;
59 m_eventType = eventTypeToSend;
60 m_pos = pos;
61 m_orient = orient;
62 }
63
64 virtual void Notify();
65
66private:
67 wxScrolledWindow *m_win;
68 wxEventType m_eventType;
69 int m_pos,
70 m_orient;
71
72 DECLARE_NO_COPY_CLASS(wxHtmlWinAutoScrollTimer)
73};
74
75void wxHtmlWinAutoScrollTimer::Notify()
76{
77 // only do all this as long as the window is capturing the mouse
78 if ( wxWindow::GetCapture() != m_win )
79 {
80 Stop();
81 }
82 else // we still capture the mouse, continue generating events
83 {
84 // first scroll the window if we are allowed to do it
85 wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
86 event1.SetEventObject(m_win);
87 if ( m_win->GetEventHandler()->ProcessEvent(event1) )
88 {
89 // and then send a pseudo mouse-move event to refresh the selection
90 wxMouseEvent event2(wxEVT_MOTION);
91 wxGetMousePosition(&event2.m_x, &event2.m_y);
92
93 // the mouse event coordinates should be client, not screen as
94 // returned by wxGetMousePosition
95 wxWindow *parentTop = m_win;
96 while ( parentTop->GetParent() )
97 parentTop = parentTop->GetParent();
98 wxPoint ptOrig = parentTop->GetPosition();
99 event2.m_x -= ptOrig.x;
100 event2.m_y -= ptOrig.y;
101
102 event2.SetEventObject(m_win);
103
104 // FIXME: we don't fill in the other members - ok?
105 m_win->GetEventHandler()->ProcessEvent(event2);
106 }
107 else // can't scroll further, stop
108 {
109 Stop();
110 }
111 }
112}
d659d703
VZ
113
114#endif // wxUSE_CLIPBOARD
1338c59a
VS
115
116
117
892aeafc
VS
118//-----------------------------------------------------------------------------
119// wxHtmlHistoryItem
120//-----------------------------------------------------------------------------
121
122// item of history list
4460b6c4 123class WXDLLIMPEXP_HTML wxHtmlHistoryItem
892aeafc
VS
124{
125public:
126 wxHtmlHistoryItem(const wxString& p, const wxString& a) {m_Page = p, m_Anchor = a, m_Pos = 0;}
127 int GetPos() const {return m_Pos;}
128 void SetPos(int p) {m_Pos = p;}
129 const wxString& GetPage() const {return m_Page;}
130 const wxString& GetAnchor() const {return m_Anchor;}
131
132private:
133 wxString m_Page;
134 wxString m_Anchor;
135 int m_Pos;
136};
5526e819 137
5526e819
VS
138
139//-----------------------------------------------------------------------------
892aeafc 140// our private arrays:
5526e819
VS
141//-----------------------------------------------------------------------------
142
892aeafc
VS
143WX_DECLARE_OBJARRAY(wxHtmlHistoryItem, wxHtmlHistoryArray);
144WX_DEFINE_OBJARRAY(wxHtmlHistoryArray);
5526e819 145
892aeafc
VS
146WX_DECLARE_LIST(wxHtmlProcessor, wxHtmlProcessorList);
147WX_DEFINE_LIST(wxHtmlProcessorList);
5526e819 148
892aeafc
VS
149//-----------------------------------------------------------------------------
150// wxHtmlWindow
151//-----------------------------------------------------------------------------
5526e819
VS
152
153
4f417130 154void wxHtmlWindow::Init()
5526e819
VS
155{
156 m_tmpMouseMoved = FALSE;
846914d1 157 m_tmpLastLink = NULL;
f6010d8f 158 m_tmpLastCell = NULL;
89de9af3 159 m_tmpCanDrawLocks = 0;
5526e819
VS
160 m_FS = new wxFileSystem();
161 m_RelatedStatusBar = -1;
162 m_RelatedFrame = NULL;
892aeafc 163 m_TitleFormat = wxT("%s");
d5db80c2 164 m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
5526e819
VS
165 m_Cell = NULL;
166 m_Parser = new wxHtmlWinParser(this);
4f9297b0 167 m_Parser->SetFS(m_FS);
5526e819
VS
168 m_HistoryPos = -1;
169 m_HistoryOn = TRUE;
892aeafc
VS
170 m_History = new wxHtmlHistoryArray;
171 m_Processors = NULL;
4f417130
VS
172 m_Style = 0;
173 SetBorders(10);
adf2eb2d
VS
174 m_selection = NULL;
175 m_makingSelection = false;
1338c59a
VS
176#if wxUSE_CLIPBOARD
177 m_timerAutoScroll = NULL;
6ce51985 178 m_lastDoubleClick = 0;
d659d703 179#endif // wxUSE_CLIPBOARD
1338c59a 180 m_backBuffer = NULL;
4f417130
VS
181}
182
790dbce3 183bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id,
4f417130 184 const wxPoint& pos, const wxSize& size,
790dbce3 185 long style, const wxString& name)
4f417130 186{
790dbce3 187 if (!wxScrolledWindow::Create(parent, id, pos, size,
4f417130
VS
188 style | wxVSCROLL | wxHSCROLL, name))
189 return FALSE;
190
a547ebff 191 m_Style = style;
4f9297b0 192 SetPage(wxT("<html><body></body></html>"));
4f417130 193 return TRUE;
5526e819
VS
194}
195
196
5526e819
VS
197wxHtmlWindow::~wxHtmlWindow()
198{
1338c59a
VS
199#if wxUSE_CLIPBOARD
200 StopAutoScrolling();
d659d703 201#endif // wxUSE_CLIPBOARD
5526e819
VS
202 HistoryClear();
203
689c4829
VZ
204 delete m_selection;
205
206 delete m_Cell;
5526e819 207
d80096a2
VZ
208 if ( m_Processors )
209 {
210 WX_CLEAR_LIST(wxHtmlProcessorList, *m_Processors);
211 }
222ed1d6 212
5526e819
VS
213 delete m_Parser;
214 delete m_FS;
892aeafc
VS
215 delete m_History;
216 delete m_Processors;
1338c59a 217 delete m_backBuffer;
5526e819
VS
218}
219
220
221
222void wxHtmlWindow::SetRelatedFrame(wxFrame* frame, const wxString& format)
223{
224 m_RelatedFrame = frame;
225 m_TitleFormat = format;
226}
227
228
229
230void wxHtmlWindow::SetRelatedStatusBar(int bar)
231{
232 m_RelatedStatusBar = bar;
233}
269e8200
RD
234
235
236
8eb2940f 237void wxHtmlWindow::SetFonts(wxString normal_face, wxString fixed_face, const int *sizes)
5526e819 238{
d5db80c2
VS
239 wxString op = m_OpenedPage;
240
4f9297b0 241 m_Parser->SetFonts(normal_face, fixed_face, sizes);
892aeafc 242 // fonts changed => contents invalid, so reload the page:
bfb9ee96 243 SetPage(wxT("<html><body></body></html>"));
d5db80c2 244 if (!op.IsEmpty()) LoadPage(op);
5526e819
VS
245}
246
247
248
249bool wxHtmlWindow::SetPage(const wxString& source)
250{
892aeafc
VS
251 wxString newsrc(source);
252
adf2eb2d
VS
253 wxDELETE(m_selection);
254
892aeafc 255 // pass HTML through registered processors:
960ba969 256 if (m_Processors || m_GlobalProcessors)
892aeafc 257 {
222ed1d6 258 wxHtmlProcessorList::compatibility_iterator nodeL, nodeG;
960ba969 259 int prL, prG;
892aeafc 260
222ed1d6
MB
261 nodeL = (m_Processors) ? m_Processors->GetFirst() : wxHtmlProcessorList::compatibility_iterator();
262 nodeG = (m_GlobalProcessors) ? m_GlobalProcessors->GetFirst() : wxHtmlProcessorList::compatibility_iterator();
960ba969
VS
263
264 // VS: there are two lists, global and local, both of them sorted by
e421922f 265 // priority. Since we have to go through _both_ lists with
960ba969
VS
266 // decreasing priority, we "merge-sort" the lists on-line by
267 // processing that one of the two heads that has higher priority
268 // in every iteration
269 while (nodeL || nodeG)
892aeafc
VS
270 {
271 prL = (nodeL) ? nodeL->GetData()->GetPriority() : -1;
960ba969
VS
272 prG = (nodeG) ? nodeG->GetData()->GetPriority() : -1;
273 if (prL > prG)
892aeafc 274 {
73348d09
VS
275 if (nodeL->GetData()->IsEnabled())
276 newsrc = nodeL->GetData()->Process(newsrc);
892aeafc
VS
277 nodeL = nodeL->GetNext();
278 }
960ba969 279 else // prL <= prG
892aeafc 280 {
73348d09
VS
281 if (nodeG->GetData()->IsEnabled())
282 newsrc = nodeG->GetData()->Process(newsrc);
960ba969 283 nodeG = nodeG->GetNext();
892aeafc
VS
284 }
285 }
286 }
5526e819 287
892aeafc
VS
288 // ...and run the parser on it:
289 wxClientDC *dc = new wxClientDC(this);
4f9297b0 290 dc->SetMapMode(wxMM_TEXT);
5526e819 291 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
d5db80c2 292 m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
4f9297b0 293 m_Parser->SetDC(dc);
33ac7e6f 294 if (m_Cell)
4f9297b0 295 {
89de9af3
VS
296 delete m_Cell;
297 m_Cell = NULL;
f61815af 298 }
892aeafc 299 m_Cell = (wxHtmlContainerCell*) m_Parser->Parse(newsrc);
5526e819 300 delete dc;
4f9297b0
VS
301 m_Cell->SetIndent(m_Borders, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
302 m_Cell->SetAlignHor(wxHTML_ALIGN_CENTER);
5526e819 303 CreateLayout();
bfb9ee96 304 if (m_tmpCanDrawLocks == 0)
892aeafc 305 Refresh();
5526e819
VS
306 return TRUE;
307}
308
39029898
VS
309bool wxHtmlWindow::AppendToPage(const wxString& source)
310{
311 return SetPage(*(GetParser()->GetSource()) + source);
312}
5526e819
VS
313
314bool wxHtmlWindow::LoadPage(const wxString& location)
315{
1ccabb81 316 wxBusyCursor busyCursor;
790dbce3 317
5526e819
VS
318 wxFSFile *f;
319 bool rt_val;
fc7dfaf8 320 bool needs_refresh = FALSE;
33ac7e6f 321
89de9af3 322 m_tmpCanDrawLocks++;
e421922f 323 if (m_HistoryOn && (m_HistoryPos != -1))
4f9297b0 324 {
960ba969 325 // store scroll position into history item:
5526e819 326 int x, y;
e421922f 327 GetViewStart(&x, &y);
892aeafc 328 (*m_History)[m_HistoryPos].SetPos(y);
5526e819
VS
329 }
330
e421922f 331 if (location[0] == wxT('#'))
4f9297b0 332 {
960ba969 333 // local anchor:
5526e819 334 wxString anch = location.Mid(1) /*1 to end*/;
89de9af3 335 m_tmpCanDrawLocks--;
5526e819 336 rt_val = ScrollToAnchor(anch);
fc7dfaf8
VS
337 m_tmpCanDrawLocks++;
338 }
33ac7e6f 339 else if (location.Find(wxT('#')) != wxNOT_FOUND && location.BeforeFirst(wxT('#')) == m_OpenedPage)
4f9297b0 340 {
fc7dfaf8
VS
341 wxString anch = location.AfterFirst(wxT('#'));
342 m_tmpCanDrawLocks--;
343 rt_val = ScrollToAnchor(anch);
344 m_tmpCanDrawLocks++;
345 }
33ac7e6f
KB
346 else if (location.Find(wxT('#')) != wxNOT_FOUND &&
347 (m_FS->GetPath() + location.BeforeFirst(wxT('#'))) == m_OpenedPage)
e421922f 348 {
fc7dfaf8
VS
349 wxString anch = location.AfterFirst(wxT('#'));
350 m_tmpCanDrawLocks--;
351 rt_val = ScrollToAnchor(anch);
352 m_tmpCanDrawLocks++;
5526e819
VS
353 }
354
33ac7e6f 355 else
4f9297b0 356 {
fc7dfaf8 357 needs_refresh = TRUE;
5526e819 358 // load&display it:
33ac7e6f 359 if (m_RelatedStatusBar != -1)
e421922f 360 {
4f9297b0 361 m_RelatedFrame->SetStatusText(_("Connecting..."), m_RelatedStatusBar);
fc7dfaf8 362 Refresh(FALSE);
5526e819 363 }
790dbce3 364
6cc4e6b8 365 f = m_Parser->OpenURL(wxHTML_URL_PAGE, location);
33ac7e6f 366
7cb9cf89
VS
367 // try to interpret 'location' as filename instead of URL:
368 if (f == NULL)
369 {
370 wxFileName fn(location);
371 wxString location2 = wxFileSystem::FileNameToURL(fn);
372 f = m_Parser->OpenURL(wxHTML_URL_PAGE, location2);
373 }
374
33ac7e6f 375 if (f == NULL)
e421922f 376 {
f6bcfd97 377 wxLogError(_("Unable to open requested HTML document: %s"), location.c_str());
89de9af3 378 m_tmpCanDrawLocks--;
5526e819
VS
379 return FALSE;
380 }
381
33ac7e6f 382 else
e421922f 383 {
222ed1d6 384 wxList::compatibility_iterator node;
5526e819
VS
385 wxString src = wxEmptyString;
386
33ac7e6f 387 if (m_RelatedStatusBar != -1)
e421922f 388 {
5526e819 389 wxString msg = _("Loading : ") + location;
4f9297b0 390 m_RelatedFrame->SetStatusText(msg, m_RelatedStatusBar);
fc7dfaf8 391 Refresh(FALSE);
5526e819
VS
392 }
393
394 node = m_Filters.GetFirst();
4f9297b0 395 while (node)
e421922f 396 {
4f9297b0
VS
397 wxHtmlFilter *h = (wxHtmlFilter*) node->GetData();
398 if (h->CanRead(*f))
e421922f 399 {
4f9297b0 400 src = h->ReadFile(*f);
5526e819
VS
401 break;
402 }
4f9297b0 403 node = node->GetNext();
5526e819 404 }
33ac7e6f 405 if (src == wxEmptyString)
e421922f 406 {
89de9af3 407 if (m_DefaultFilter == NULL) m_DefaultFilter = GetDefaultFilter();
4f9297b0 408 src = m_DefaultFilter->ReadFile(*f);
89de9af3 409 }
5526e819 410
4f9297b0 411 m_FS->ChangePathTo(f->GetLocation());
5526e819 412 rt_val = SetPage(src);
4f9297b0 413 m_OpenedPage = f->GetLocation();
33ac7e6f 414 if (f->GetAnchor() != wxEmptyString)
e421922f 415 {
4f9297b0 416 ScrollToAnchor(f->GetAnchor());
5526e819
VS
417 }
418
419 delete f;
420
4f9297b0 421 if (m_RelatedStatusBar != -1) m_RelatedFrame->SetStatusText(_("Done"), m_RelatedStatusBar);
5526e819
VS
422 }
423 }
424
4f9297b0
VS
425 if (m_HistoryOn) // add this page to history there:
426 {
892aeafc 427 int c = m_History->GetCount() - (m_HistoryPos + 1);
5526e819 428
0cb9cfb2 429 if (m_HistoryPos < 0 ||
ee19c324
VS
430 (*m_History)[m_HistoryPos].GetPage() != m_OpenedPage ||
431 (*m_History)[m_HistoryPos].GetAnchor() != m_OpenedAnchor)
432 {
433 m_HistoryPos++;
434 for (int i = 0; i < c; i++)
b54e41c5 435 m_History->RemoveAt(m_HistoryPos);
ee19c324
VS
436 m_History->Add(new wxHtmlHistoryItem(m_OpenedPage, m_OpenedAnchor));
437 }
5526e819
VS
438 }
439
096824d7
VS
440 if (m_OpenedPageTitle == wxEmptyString)
441 OnSetTitle(wxFileNameFromPath(m_OpenedPage));
fc7dfaf8 442
33ac7e6f 443 if (needs_refresh)
4f9297b0 444 {
fc7dfaf8
VS
445 m_tmpCanDrawLocks--;
446 Refresh();
447 }
448 else
449 m_tmpCanDrawLocks--;
450
5526e819
VS
451 return rt_val;
452}
453
454
7cb9cf89
VS
455bool wxHtmlWindow::LoadFile(const wxFileName& filename)
456{
457 wxString url = wxFileSystem::FileNameToURL(filename);
458 return LoadPage(url);
459}
460
5526e819
VS
461
462bool wxHtmlWindow::ScrollToAnchor(const wxString& anchor)
463{
4f9297b0 464 const wxHtmlCell *c = m_Cell->Find(wxHTML_COND_ISANCHOR, &anchor);
f3c82859
VS
465 if (!c)
466 {
f6bcfd97 467 wxLogWarning(_("HTML anchor %s does not exist."), anchor.c_str());
f3c82859
VS
468 return FALSE;
469 }
33ac7e6f 470 else
4f9297b0 471 {
5526e819 472 int y;
269e8200 473
4f9297b0 474 for (y = 0; c != NULL; c = c->GetParent()) y += c->GetPosY();
efba2b89 475 Scroll(-1, y / wxHTML_SCROLL_STEP);
5526e819
VS
476 m_OpenedAnchor = anchor;
477 return TRUE;
478 }
479}
480
481
d5db80c2 482void wxHtmlWindow::OnSetTitle(const wxString& title)
5526e819 483{
33ac7e6f 484 if (m_RelatedFrame)
4f9297b0 485 {
5526e819
VS
486 wxString tit;
487 tit.Printf(m_TitleFormat, title.c_str());
4f9297b0 488 m_RelatedFrame->SetTitle(tit);
5526e819 489 }
d5db80c2 490 m_OpenedPageTitle = title;
5526e819
VS
491}
492
493
494
495
496
497void wxHtmlWindow::CreateLayout()
498{
499 int ClientWidth, ClientHeight;
500
501 if (!m_Cell) return;
a547ebff 502
33ac7e6f 503 if (m_Style & wxHW_SCROLLBAR_NEVER)
4f9297b0
VS
504 {
505 SetScrollbars(wxHTML_SCROLL_STEP, 1, m_Cell->GetWidth() / wxHTML_SCROLL_STEP, 0); // always off
a547ebff 506 GetClientSize(&ClientWidth, &ClientHeight);
4f9297b0 507 m_Cell->Layout(ClientWidth);
a547ebff
VS
508 }
509
510 else {
511 GetClientSize(&ClientWidth, &ClientHeight);
4f9297b0 512 m_Cell->Layout(ClientWidth);
33ac7e6f 513 if (ClientHeight < m_Cell->GetHeight() + GetCharHeight())
e421922f 514 {
f3bcfd9b
VS
515 SetScrollbars(
516 wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
4f9297b0
VS
517 m_Cell->GetWidth() / wxHTML_SCROLL_STEP,
518 (m_Cell->GetHeight() + GetCharHeight()) / wxHTML_SCROLL_STEP
f3bcfd9b 519 /*cheat: top-level frag is always container*/);
a547ebff 520 }
4f9297b0 521 else /* we fit into window, no need for scrollbars */
e421922f 522 {
4f9297b0 523 SetScrollbars(wxHTML_SCROLL_STEP, 1, m_Cell->GetWidth() / wxHTML_SCROLL_STEP, 0); // disable...
89de9af3 524 GetClientSize(&ClientWidth, &ClientHeight);
4f9297b0 525 m_Cell->Layout(ClientWidth); // ...and relayout
89de9af3 526 }
a547ebff 527 }
5526e819
VS
528}
529
269e8200 530
5526e819
VS
531
532void wxHtmlWindow::ReadCustomization(wxConfigBase *cfg, wxString path)
533{
534 wxString oldpath;
535 wxString tmp;
d5db80c2
VS
536 int p_fontsizes[7];
537 wxString p_fff, p_ffn;
5526e819 538
33ac7e6f 539 if (path != wxEmptyString)
4f9297b0
VS
540 {
541 oldpath = cfg->GetPath();
542 cfg->SetPath(path);
5526e819
VS
543 }
544
892aeafc
VS
545 m_Borders = cfg->Read(wxT("wxHtmlWindow/Borders"), m_Borders);
546 p_fff = cfg->Read(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser->m_FontFaceFixed);
547 p_ffn = cfg->Read(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser->m_FontFaceNormal);
bfb9ee96 548 for (int i = 0; i < 7; i++)
4f9297b0 549 {
66a77a74 550 tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
4f9297b0 551 p_fontsizes[i] = cfg->Read(tmp, m_Parser->m_FontsSizes[i]);
5526e819 552 }
8eb2940f 553 SetFonts(p_ffn, p_fff, p_fontsizes);
5526e819
VS
554
555 if (path != wxEmptyString)
4f9297b0 556 cfg->SetPath(oldpath);
5526e819
VS
557}
558
559
560
561void wxHtmlWindow::WriteCustomization(wxConfigBase *cfg, wxString path)
562{
563 wxString oldpath;
564 wxString tmp;
565
33ac7e6f 566 if (path != wxEmptyString)
4f9297b0
VS
567 {
568 oldpath = cfg->GetPath();
569 cfg->SetPath(path);
5526e819
VS
570 }
571
892aeafc
VS
572 cfg->Write(wxT("wxHtmlWindow/Borders"), (long) m_Borders);
573 cfg->Write(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser->m_FontFaceFixed);
574 cfg->Write(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser->m_FontFaceNormal);
bfb9ee96 575 for (int i = 0; i < 7; i++)
4f9297b0 576 {
66a77a74 577 tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
4f9297b0 578 cfg->Write(tmp, (long) m_Parser->m_FontsSizes[i]);
5526e819
VS
579 }
580
581 if (path != wxEmptyString)
4f9297b0 582 cfg->SetPath(oldpath);
5526e819
VS
583}
584
585
586
587bool wxHtmlWindow::HistoryBack()
588{
589 wxString a, l;
590
591 if (m_HistoryPos < 1) return FALSE;
592
bbda1088
VS
593 // store scroll position into history item:
594 int x, y;
e421922f 595 GetViewStart(&x, &y);
892aeafc 596 (*m_History)[m_HistoryPos].SetPos(y);
bbda1088
VS
597
598 // go to previous position:
5526e819
VS
599 m_HistoryPos--;
600
892aeafc
VS
601 l = (*m_History)[m_HistoryPos].GetPage();
602 a = (*m_History)[m_HistoryPos].GetAnchor();
5526e819 603 m_HistoryOn = FALSE;
89de9af3 604 m_tmpCanDrawLocks++;
5526e819 605 if (a == wxEmptyString) LoadPage(l);
fc7dfaf8 606 else LoadPage(l + wxT("#") + a);
5526e819 607 m_HistoryOn = TRUE;
89de9af3 608 m_tmpCanDrawLocks--;
892aeafc 609 Scroll(0, (*m_History)[m_HistoryPos].GetPos());
5526e819
VS
610 Refresh();
611 return TRUE;
612}
613
1b113a81
VS
614bool wxHtmlWindow::HistoryCanBack()
615{
616 if (m_HistoryPos < 1) return FALSE;
617 return TRUE ;
618}
5526e819
VS
619
620
621bool wxHtmlWindow::HistoryForward()
622{
623 wxString a, l;
624
625 if (m_HistoryPos == -1) return FALSE;
892aeafc 626 if (m_HistoryPos >= (int)m_History->GetCount() - 1)return FALSE;
5526e819
VS
627
628 m_OpenedPage = wxEmptyString; // this will disable adding new entry into history in LoadPage()
629
630 m_HistoryPos++;
892aeafc
VS
631 l = (*m_History)[m_HistoryPos].GetPage();
632 a = (*m_History)[m_HistoryPos].GetAnchor();
5526e819 633 m_HistoryOn = FALSE;
89de9af3 634 m_tmpCanDrawLocks++;
5526e819 635 if (a == wxEmptyString) LoadPage(l);
fc7dfaf8 636 else LoadPage(l + wxT("#") + a);
5526e819 637 m_HistoryOn = TRUE;
89de9af3 638 m_tmpCanDrawLocks--;
892aeafc 639 Scroll(0, (*m_History)[m_HistoryPos].GetPos());
5526e819
VS
640 Refresh();
641 return TRUE;
642}
643
1b113a81
VS
644bool wxHtmlWindow::HistoryCanForward()
645{
646 if (m_HistoryPos == -1) return FALSE;
892aeafc 647 if (m_HistoryPos >= (int)m_History->GetCount() - 1)return FALSE;
1b113a81
VS
648 return TRUE ;
649}
5526e819
VS
650
651
652void wxHtmlWindow::HistoryClear()
653{
892aeafc 654 m_History->Empty();
5526e819
VS
655 m_HistoryPos = -1;
656}
657
892aeafc
VS
658void wxHtmlWindow::AddProcessor(wxHtmlProcessor *processor)
659{
660 if (!m_Processors)
661 {
662 m_Processors = new wxHtmlProcessorList;
892aeafc 663 }
222ed1d6 664 wxHtmlProcessorList::compatibility_iterator node;
bfb9ee96 665
892aeafc
VS
666 for (node = m_Processors->GetFirst(); node; node = node->GetNext())
667 {
bfb9ee96 668 if (processor->GetPriority() > node->GetData()->GetPriority())
892aeafc
VS
669 {
670 m_Processors->Insert(node, processor);
960ba969 671 return;
892aeafc
VS
672 }
673 }
960ba969 674 m_Processors->Append(processor);
892aeafc
VS
675}
676
960ba969 677/*static */ void wxHtmlWindow::AddGlobalProcessor(wxHtmlProcessor *processor)
892aeafc 678{
960ba969 679 if (!m_GlobalProcessors)
892aeafc 680 {
960ba969 681 m_GlobalProcessors = new wxHtmlProcessorList;
892aeafc 682 }
222ed1d6 683 wxHtmlProcessorList::compatibility_iterator node;
e421922f 684
960ba969 685 for (node = m_GlobalProcessors->GetFirst(); node; node = node->GetNext())
892aeafc 686 {
bfb9ee96 687 if (processor->GetPriority() > node->GetData()->GetPriority())
892aeafc 688 {
960ba969
VS
689 m_GlobalProcessors->Insert(node, processor);
690 return;
892aeafc
VS
691 }
692 }
960ba969 693 m_GlobalProcessors->Append(processor);
892aeafc
VS
694}
695
5526e819
VS
696
697
698wxList wxHtmlWindow::m_Filters;
a76015e6 699wxHtmlFilter *wxHtmlWindow::m_DefaultFilter = NULL;
960ba969 700wxHtmlProcessorList *wxHtmlWindow::m_GlobalProcessors = NULL;
a76015e6
VS
701
702void wxHtmlWindow::CleanUpStatics()
703{
eeb029a9 704 wxDELETE(m_DefaultFilter);
222ed1d6
MB
705 WX_CLEAR_LIST(wxList, m_Filters);
706 if (m_GlobalProcessors)
707 WX_CLEAR_LIST(wxHtmlProcessorList, *m_GlobalProcessors);
eeb029a9 708 wxDELETE(m_GlobalProcessors);
a76015e6
VS
709}
710
711
5526e819
VS
712
713void wxHtmlWindow::AddFilter(wxHtmlFilter *filter)
714{
5526e819
VS
715 m_Filters.Append(filter);
716}
717
718
36c4ff4d
VS
719bool wxHtmlWindow::IsSelectionEnabled() const
720{
721#if wxUSE_CLIPBOARD
722 return !(m_Style & wxHW_NO_SELECTION);
723#else
724 return false;
725#endif
726}
d659d703 727
e3774124 728
1338c59a 729#if wxUSE_CLIPBOARD
e3774124
VS
730wxString wxHtmlWindow::SelectionToText()
731{
732 if ( !m_selection )
733 return wxEmptyString;
734
f30e67db
VS
735 wxClientDC dc(this);
736
e3774124
VS
737 const wxHtmlCell *end = m_selection->GetToCell();
738 wxString text;
739 wxHtmlTerminalCellsInterator i(m_selection->GetFromCell(), end);
740 if ( i )
741 {
742 text << i->ConvertToText(m_selection);
743 ++i;
744 }
745 const wxHtmlCell *prev = *i;
746 while ( i )
747 {
748 if ( prev->GetParent() != i->GetParent() )
749 text << _T('\n');
750 text << i->ConvertToText(*i == end ? m_selection : NULL);
751 prev = *i;
752 ++i;
753 }
754 return text;
755}
756
d659d703
VZ
757#endif // wxUSE_CLIPBOARD
758
8feaa81f 759bool wxHtmlWindow::CopySelection(ClipboardType t)
e3774124 760{
d659d703 761#if wxUSE_CLIPBOARD
e3774124
VS
762 if ( m_selection )
763 {
d659d703 764#ifdef __UNIX__
e3774124 765 wxTheClipboard->UsePrimarySelection(t == Primary);
d659d703
VZ
766#else // !__UNIX__
767 // Primary selection exists only under X11, so don't do anything under
768 // the other platforms when we try to access it
769 //
770 // TODO: this should be abstracted at wxClipboard level!
771 if ( t == Primary )
8feaa81f 772 return false;
d659d703
VZ
773#endif // __UNIX__/!__UNIX__
774
e3774124
VS
775 if ( wxTheClipboard->Open() )
776 {
d659d703 777 const wxString txt(SelectionToText());
e3774124
VS
778 wxTheClipboard->SetData(new wxTextDataObject(txt));
779 wxTheClipboard->Close();
780 wxLogTrace(_T("wxhtmlselection"),
781 _("Copied to clipboard:\"%s\""), txt.c_str());
8feaa81f
VZ
782
783 return true;
e3774124
VS
784 }
785 }
d659d703 786#endif // wxUSE_CLIPBOARD
8feaa81f
VZ
787
788 return false;
e3774124 789}
5526e819
VS
790
791
0b2dadd3 792void wxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link)
5526e819 793{
31d8b4ad
VS
794 const wxMouseEvent *e = link.GetEvent();
795 if (e == NULL || e->LeftUp())
796 LoadPage(link.GetHref());
5526e819
VS
797}
798
f6010d8f
VZ
799void wxHtmlWindow::OnCellClicked(wxHtmlCell *cell,
800 wxCoord x, wxCoord y,
801 const wxMouseEvent& event)
19193a2c 802{
f6010d8f 803 wxCHECK_RET( cell, _T("can't be called with NULL cell") );
5526e819 804
f6010d8f
VZ
805 cell->OnMouseClick(this, x, y, event);
806}
807
808void wxHtmlWindow::OnCellMouseHover(wxHtmlCell * WXUNUSED(cell),
809 wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
810{
811 // do nothing here
812}
5526e819 813
fc7a2a60 814void wxHtmlWindow::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
1338c59a
VS
815{
816}
817
818void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
5526e819 819{
1338c59a
VS
820 wxPaintDC dc(this);
821
b835e9bf 822 if (m_tmpCanDrawLocks > 0 || m_Cell == NULL) return;
5526e819 823
b835e9bf 824 int x, y;
e421922f 825 GetViewStart(&x, &y);
1338c59a
VS
826 wxRect rect = GetUpdateRegion().GetBox();
827 wxSize sz = GetSize();
828
829 wxMemoryDC dcm;
830 if ( !m_backBuffer )
831 m_backBuffer = new wxBitmap(sz.x, sz.y);
d659d703 832 dcm.SelectObject(*m_backBuffer);
1338c59a
VS
833 dcm.SetBackground(wxBrush(GetBackgroundColour(), wxSOLID));
834 dcm.Clear();
835 PrepareDC(dcm);
836 dcm.SetMapMode(wxMM_TEXT);
837 dcm.SetBackgroundMode(wxTRANSPARENT);
d659d703 838
f30e67db
VS
839 wxHtmlRenderingInfo rinfo;
840 wxDefaultHtmlRenderingStyle rstyle;
841 rinfo.SetSelection(m_selection);
842 rinfo.SetStyle(&rstyle);
1338c59a 843 m_Cell->Draw(dcm, 0, 0,
790dbce3 844 y * wxHTML_SCROLL_STEP + rect.GetTop(),
36c4ff4d 845 y * wxHTML_SCROLL_STEP + rect.GetBottom(),
f30e67db 846 rinfo);
03693319
VS
847
848//#define DEBUG_HTML_SELECTION
849#ifdef DEBUG_HTML_SELECTION
850 {
851 int xc, yc, x, y;
852 wxGetMousePosition(&xc, &yc);
853 ScreenToClient(&xc, &yc);
854 CalcUnscrolledPosition(xc, yc, &x, &y);
855 wxHtmlCell *at = m_Cell->FindCellByPos(x, y);
856 wxHtmlCell *before =
857 m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_BEFORE);
858 wxHtmlCell *after =
859 m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_AFTER);
860
861 dcm.SetBrush(*wxTRANSPARENT_BRUSH);
862 dcm.SetPen(*wxBLACK_PEN);
863 if (at)
864 dcm.DrawRectangle(at->GetAbsPos(),
865 wxSize(at->GetWidth(),at->GetHeight()));
866 dcm.SetPen(*wxGREEN_PEN);
867 if (before)
868 dcm.DrawRectangle(before->GetAbsPos().x+1, before->GetAbsPos().y+1,
869 before->GetWidth()-2,before->GetHeight()-2);
870 dcm.SetPen(*wxRED_PEN);
871 if (after)
872 dcm.DrawRectangle(after->GetAbsPos().x+2, after->GetAbsPos().y+2,
873 after->GetWidth()-4,after->GetHeight()-4);
874 }
875#endif
748418c0 876
1338c59a
VS
877 dcm.SetDeviceOrigin(0,0);
878 dc.Blit(0, rect.GetTop(),
879 sz.x, rect.GetBottom() - rect.GetTop() + 1,
880 &dcm,
881 0, rect.GetTop());
5526e819
VS
882}
883
884
885
886
887void wxHtmlWindow::OnSize(wxSizeEvent& event)
888{
1338c59a
VS
889 wxDELETE(m_backBuffer);
890
5526e819
VS
891 wxScrolledWindow::OnSize(event);
892 CreateLayout();
1338c59a
VS
893
894 // Recompute selection if necessary:
895 if ( m_selection )
896 {
897 m_selection->Set(m_selection->GetFromCell(),
898 m_selection->GetToCell());
899 m_selection->ClearPrivPos();
900 }
d659d703 901
f6bcfd97 902 Refresh();
5526e819
VS
903}
904
905
fc7a2a60 906void wxHtmlWindow::OnMouseMove(wxMouseEvent& WXUNUSED(event))
5526e819 907{
31d8b4ad
VS
908 m_tmpMouseMoved = true;
909}
5526e819 910
adf2eb2d 911void wxHtmlWindow::OnMouseDown(wxMouseEvent& event)
31d8b4ad 912{
0994d968 913#if wxUSE_CLIPBOARD
adf2eb2d 914 if ( event.LeftDown() && IsSelectionEnabled() )
4f9297b0 915 {
0994d968
VS
916 const long TRIPLECLICK_LEN = 200; // 0.2 sec after doubleclick
917 if ( wxGetLocalTimeMillis() - m_lastDoubleClick <= TRIPLECLICK_LEN )
adf2eb2d 918 {
0994d968 919 SelectLine(CalcUnscrolledPosition(event.GetPosition()));
d659d703 920
5de65c69 921 (void) CopySelection();
adf2eb2d 922 }
0994d968 923 else
d659d703 924 {
0994d968 925 m_makingSelection = true;
d659d703 926
0994d968
VS
927 if ( m_selection )
928 {
929 wxDELETE(m_selection);
930 Refresh();
931 }
932 m_tmpSelFromPos = CalcUnscrolledPosition(event.GetPosition());
933 m_tmpSelFromCell = NULL;
5526e819 934
0994d968
VS
935 CaptureMouse();
936 }
adf2eb2d 937 }
d659d703 938#endif // wxUSE_CLIPBOARD
adf2eb2d 939}
5526e819 940
adf2eb2d
VS
941void wxHtmlWindow::OnMouseUp(wxMouseEvent& event)
942{
1338c59a 943#if wxUSE_CLIPBOARD
adf2eb2d
VS
944 if ( m_makingSelection )
945 {
946 ReleaseMouse();
947 m_makingSelection = false;
948
949 // did the user move the mouse far enough from starting point?
8feaa81f 950 if ( CopySelection(Primary) )
adf2eb2d
VS
951 {
952 // we don't want mouse up event that ended selecting to be
953 // handled as mouse click and e.g. follow hyperlink:
954 return;
955 }
956 }
d659d703
VZ
957#endif // wxUSE_CLIPBOARD
958
adf2eb2d
VS
959 SetFocus();
960 if ( m_Cell )
961 {
962 wxPoint pos = CalcUnscrolledPosition(event.GetPosition());
31d8b4ad 963 wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
f6010d8f 964
d659d703
VZ
965 // check is needed because FindCellByPos returns terminal cell and
966 // containers may have empty borders -- in this case NULL will be
967 // returned
31d8b4ad
VS
968 if ( cell )
969 OnCellClicked(cell, pos.x, pos.y, event);
5526e819
VS
970 }
971}
972
973
974
5180055b
JS
975void wxHtmlWindow::OnInternalIdle()
976{
977 wxWindow::OnInternalIdle();
978
33ac7e6f 979 if (m_tmpMouseMoved && (m_Cell != NULL))
4f9297b0 980 {
03693319
VS
981#ifdef DEBUG_HTML_SELECTION
982 Refresh();
983#endif
adf2eb2d
VS
984 int xc, yc, x, y;
985 wxGetMousePosition(&xc, &yc);
986 ScreenToClient(&xc, &yc);
987 CalcUnscrolledPosition(xc, yc, &x, &y);
0cb9cfb2 988
f6010d8f 989 wxHtmlCell *cell = m_Cell->FindCellByPos(x, y);
adf2eb2d
VS
990
991 // handle selection update:
992 if ( m_makingSelection )
993 {
adf2eb2d 994 if ( !m_tmpSelFromCell )
748418c0
VS
995 m_tmpSelFromCell = m_Cell->FindCellByPos(
996 m_tmpSelFromPos.x,m_tmpSelFromPos.y);
03693319
VS
997
998 // NB: a trick - we adjust selFromPos to be upper left or bottom
999 // right corner of the first cell of the selection depending
1000 // on whether the mouse is moving to the right or to the left.
1001 // This gives us more "natural" behaviour when selecting
1002 // a line (specifically, first cell of the next line is not
1003 // included if you drag selection from left to right over
1004 // entire line):
1005 wxPoint dirFromPos;
1006 if ( !m_tmpSelFromCell )
1007 {
1008 dirFromPos = m_tmpSelFromPos;
1009 }
1010 else
1011 {
1012 dirFromPos = m_tmpSelFromCell->GetAbsPos();
1013 if ( x < m_tmpSelFromPos.x )
1014 {
1015 dirFromPos.x += m_tmpSelFromCell->GetWidth();
1016 dirFromPos.y += m_tmpSelFromCell->GetHeight();
1017 }
1018 }
1019 bool goingDown = dirFromPos.y < y ||
1020 (dirFromPos.y == y && dirFromPos.x < x);
1021
1022 // determine selection span:
748418c0 1023 if ( /*still*/ !m_tmpSelFromCell )
adf2eb2d
VS
1024 {
1025 if (goingDown)
1026 {
5a1597e9
VS
1027 m_tmpSelFromCell = m_Cell->FindCellByPos(
1028 m_tmpSelFromPos.x,m_tmpSelFromPos.y,
1029 wxHTML_FIND_NEAREST_AFTER);
adf2eb2d
VS
1030 if (!m_tmpSelFromCell)
1031 m_tmpSelFromCell = m_Cell->GetFirstTerminal();
1032 }
1033 else
1034 {
5a1597e9
VS
1035 m_tmpSelFromCell = m_Cell->FindCellByPos(
1036 m_tmpSelFromPos.x,m_tmpSelFromPos.y,
1037 wxHTML_FIND_NEAREST_BEFORE);
adf2eb2d
VS
1038 if (!m_tmpSelFromCell)
1039 m_tmpSelFromCell = m_Cell->GetLastTerminal();
1040 }
1041 }
1042
1043 wxHtmlCell *selcell = cell;
1044 if (!selcell)
1045 {
1046 if (goingDown)
1047 {
1048 selcell = m_Cell->FindCellByPos(x, y,
03693319 1049 wxHTML_FIND_NEAREST_BEFORE);
adf2eb2d
VS
1050 if (!selcell)
1051 selcell = m_Cell->GetLastTerminal();
1052 }
1053 else
1054 {
1055 selcell = m_Cell->FindCellByPos(x, y,
03693319 1056 wxHTML_FIND_NEAREST_AFTER);
adf2eb2d
VS
1057 if (!selcell)
1058 selcell = m_Cell->GetFirstTerminal();
1059 }
1060 }
1061
1062 // NB: it may *rarely* happen that the code above didn't find one
1063 // of the cells, e.g. if wxHtmlWindow doesn't contain any
d659d703 1064 // visible cells.
adf2eb2d 1065 if ( selcell && m_tmpSelFromCell )
d659d703 1066 {
adf2eb2d
VS
1067 if ( !m_selection )
1068 {
1069 // start selecting only if mouse movement was big enough
1070 // (otherwise it was meant as mouse click, not selection):
1071 const int PRECISION = 2;
1072 wxPoint diff = m_tmpSelFromPos - wxPoint(x,y);
1073 if (abs(diff.x) > PRECISION || abs(diff.y) > PRECISION)
1074 {
1075 m_selection = new wxHtmlSelection();
1076 }
1077 }
1078 if ( m_selection )
1079 {
e3774124 1080 if ( m_tmpSelFromCell->IsBefore(selcell) )
adf2eb2d
VS
1081 {
1082 m_selection->Set(m_tmpSelFromPos, m_tmpSelFromCell,
f30e67db 1083 wxPoint(x,y), selcell); }
adf2eb2d
VS
1084 else
1085 {
1086 m_selection->Set(wxPoint(x,y), selcell,
1087 m_tmpSelFromPos, m_tmpSelFromCell);
1088 }
1338c59a
VS
1089 m_selection->ClearPrivPos();
1090 Refresh();
adf2eb2d
VS
1091 }
1092 }
1093 }
d659d703 1094
adf2eb2d 1095 // handle cursor and status bar text changes:
f6010d8f 1096 if ( cell != m_tmpLastCell )
e421922f 1097 {
f6010d8f 1098 wxHtmlLinkInfo *lnk = cell ? cell->GetLink(x, y) : NULL;
77bae5e2
VS
1099 wxCursor cur;
1100 if (cell)
1101 cur = cell->GetCursor();
1102 else
1103 cur = *wxSTANDARD_CURSOR;
1104 SetCursor(cur);
f6010d8f
VZ
1105
1106 if (lnk != m_tmpLastLink)
e421922f 1107 {
f6010d8f
VZ
1108 if (lnk == NULL)
1109 {
f6010d8f 1110 if (m_RelatedStatusBar != -1)
31eefb99
VS
1111 m_RelatedFrame->SetStatusText(wxEmptyString,
1112 m_RelatedStatusBar);
f6010d8f
VZ
1113 }
1114 else
1115 {
f6010d8f 1116 if (m_RelatedStatusBar != -1)
31eefb99
VS
1117 m_RelatedFrame->SetStatusText(lnk->GetHref(),
1118 m_RelatedStatusBar);
f6010d8f
VZ
1119 }
1120 m_tmpLastLink = lnk;
622ea783 1121 }
f6010d8f
VZ
1122
1123 m_tmpLastCell = cell;
5526e819 1124 }
f6010d8f
VZ
1125 else // mouse moved but stayed in the same cell
1126 {
1127 if ( cell )
1128 OnCellMouseHover(cell, x, y);
1129 }
1130
5526e819
VS
1131 m_tmpMouseMoved = FALSE;
1132 }
1133}
1134
e3774124 1135#if wxUSE_CLIPBOARD
1338c59a
VS
1136void wxHtmlWindow::StopAutoScrolling()
1137{
1138 if ( m_timerAutoScroll )
1139 {
1140 wxDELETE(m_timerAutoScroll);
1141 }
1142}
1143
1144void wxHtmlWindow::OnMouseEnter(wxMouseEvent& event)
1145{
1146 StopAutoScrolling();
1147 event.Skip();
1148}
1149
1150void wxHtmlWindow::OnMouseLeave(wxMouseEvent& event)
1151{
1152 // don't prevent the usual processing of the event from taking place
1153 event.Skip();
1154
1155 // when a captured mouse leave a scrolled window we start generate
1156 // scrolling events to allow, for example, extending selection beyond the
1157 // visible area in some controls
1158 if ( wxWindow::GetCapture() == this )
1159 {
1160 // where is the mouse leaving?
1161 int pos, orient;
1162 wxPoint pt = event.GetPosition();
1163 if ( pt.x < 0 )
1164 {
1165 orient = wxHORIZONTAL;
1166 pos = 0;
1167 }
1168 else if ( pt.y < 0 )
1169 {
1170 orient = wxVERTICAL;
1171 pos = 0;
1172 }
1173 else // we're lower or to the right of the window
1174 {
1175 wxSize size = GetClientSize();
1176 if ( pt.x > size.x )
1177 {
1178 orient = wxHORIZONTAL;
1179 pos = GetVirtualSize().x / wxHTML_SCROLL_STEP;
1180 }
1181 else if ( pt.y > size.y )
1182 {
1183 orient = wxVERTICAL;
1184 pos = GetVirtualSize().y / wxHTML_SCROLL_STEP;
1185 }
1186 else // this should be impossible
1187 {
1188 // but seems to happen sometimes under wxMSW - maybe it's a bug
1189 // there but for now just ignore it
1190
1191 //wxFAIL_MSG( _T("can't understand where has mouse gone") );
1192
1193 return;
1194 }
1195 }
1196
1197 // only start the auto scroll timer if the window can be scrolled in
1198 // this direction
1199 if ( !HasScrollbar(orient) )
1200 return;
1201
1202 delete m_timerAutoScroll;
1203 m_timerAutoScroll = new wxHtmlWinAutoScrollTimer
1204 (
1205 this,
1206 pos == 0 ? wxEVT_SCROLLWIN_LINEUP
1207 : wxEVT_SCROLLWIN_LINEDOWN,
1208 pos,
1209 orient
1210 );
1211 m_timerAutoScroll->Start(50); // FIXME: make configurable
1212 }
1213}
1214
e3774124
VS
1215void wxHtmlWindow::OnKeyUp(wxKeyEvent& event)
1216{
31eefb99
VS
1217 if ( IsSelectionEnabled() &&
1218 event.GetKeyCode() == 'C' && event.ControlDown() )
e3774124 1219 {
5de65c69 1220 (void) CopySelection();
e3774124 1221 }
e3774124
VS
1222}
1223
fc7a2a60 1224void wxHtmlWindow::OnCopy(wxCommandEvent& WXUNUSED(event))
e3774124 1225{
5de65c69 1226 (void) CopySelection();
e3774124 1227}
d659d703 1228
31eefb99
VS
1229void wxHtmlWindow::OnDoubleClick(wxMouseEvent& event)
1230{
1231 // select word under cursor:
1232 if ( IsSelectionEnabled() )
1233 {
0994d968 1234 SelectWord(CalcUnscrolledPosition(event.GetPosition()));
d659d703 1235
5de65c69 1236 (void) CopySelection(Primary);
d659d703 1237
0994d968 1238 m_lastDoubleClick = wxGetLocalTimeMillis();
31eefb99
VS
1239 }
1240 else
1241 event.Skip();
1242}
0994d968
VS
1243
1244void wxHtmlWindow::SelectWord(const wxPoint& pos)
1245{
1246 wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
1247 if ( cell )
1248 {
1249 delete m_selection;
1250 m_selection = new wxHtmlSelection();
1251 m_selection->Set(cell, cell);
1252 RefreshRect(wxRect(CalcScrolledPosition(cell->GetAbsPos()),
1253 wxSize(cell->GetWidth(), cell->GetHeight())));
1254 }
1255}
1256
1257void wxHtmlWindow::SelectLine(const wxPoint& pos)
1258{
1259 wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
1260 if ( cell )
1261 {
1262 // We use following heuristic to find a "line": let the line be all
1263 // cells in same container as the cell under mouse cursor that are
1264 // neither completely above nor completely bellow the clicked cell
1265 // (i.e. are likely to be words positioned on same line of text).
d659d703 1266
0994d968
VS
1267 int y1 = cell->GetAbsPos().y;
1268 int y2 = y1 + cell->GetHeight();
1269 int y;
1270 const wxHtmlCell *c;
1271 const wxHtmlCell *before = NULL;
1272 const wxHtmlCell *after = NULL;
1273
1274 // find last cell of line:
1275 for ( c = cell->GetNext(); c; c = c->GetNext())
1276 {
1277 y = c->GetAbsPos().y;
1278 if ( y + c->GetHeight() > y1 && y < y2 )
1279 after = c;
1280 else
1281 break;
1282 }
1283 if ( !after )
1284 after = cell;
1285
1286 // find first cell of line:
1287 for ( c = cell->GetParent()->GetFirstChild();
1288 c && c != cell; c = c->GetNext())
1289 {
1290 y = c->GetAbsPos().y;
1291 if ( y + c->GetHeight() > y1 && y < y2 )
1292 {
1293 if ( ! before )
1294 before = c;
1295 }
1296 else
1297 before = NULL;
1298 }
1299 if ( !before )
1300 before = cell;
d659d703 1301
0994d968
VS
1302 delete m_selection;
1303 m_selection = new wxHtmlSelection();
1304 m_selection->Set(before, after);
d659d703 1305
0994d968
VS
1306 Refresh();
1307 }
1308}
d659d703 1309#endif // wxUSE_CLIPBOARD
e3774124
VS
1310
1311
5526e819 1312
bfb9ee96 1313IMPLEMENT_ABSTRACT_CLASS(wxHtmlProcessor,wxObject)
5526e819 1314
786a2425
SC
1315#if wxUSE_EXTENDED_RTTI
1316IMPLEMENT_DYNAMIC_CLASS_XTI(wxHtmlWindow, wxScrolledWindow,"wx/html/htmlwin.h")
1317
459f2add 1318wxBEGIN_PROPERTIES_TABLE(wxHtmlWindow)
786a2425
SC
1319/*
1320 TODO PROPERTIES
1321 style , wxHW_SCROLLBAR_AUTO
1322 borders , (dimension)
1323 url , string
1324 htmlcode , string
1325*/
459f2add 1326wxEND_PROPERTIES_TABLE()
786a2425 1327
459f2add
SC
1328wxBEGIN_HANDLERS_TABLE(wxHtmlWindow)
1329wxEND_HANDLERS_TABLE()
786a2425 1330
459f2add 1331wxCONSTRUCTOR_5( wxHtmlWindow , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
786a2425 1332#else
5526e819 1333IMPLEMENT_DYNAMIC_CLASS(wxHtmlWindow,wxScrolledWindow)
786a2425 1334#endif
5526e819
VS
1335
1336BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
1337 EVT_SIZE(wxHtmlWindow::OnSize)
adf2eb2d
VS
1338 EVT_LEFT_DOWN(wxHtmlWindow::OnMouseDown)
1339 EVT_LEFT_UP(wxHtmlWindow::OnMouseUp)
1340 EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp)
31d8b4ad 1341 EVT_MOTION(wxHtmlWindow::OnMouseMove)
1338c59a
VS
1342 EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground)
1343 EVT_PAINT(wxHtmlWindow::OnPaint)
e3774124 1344#if wxUSE_CLIPBOARD
31eefb99 1345 EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick)
1338c59a
VS
1346 EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter)
1347 EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave)
e3774124
VS
1348 EVT_KEY_UP(wxHtmlWindow::OnKeyUp)
1349 EVT_MENU(wxID_COPY, wxHtmlWindow::OnCopy)
d659d703 1350#endif // wxUSE_CLIPBOARD
5526e819
VS
1351END_EVENT_TABLE()
1352
1353
1354
1355
1356
a76015e6
VS
1357// A module to allow initialization/cleanup
1358// without calling these functions from app.cpp or from
1359// the user's application.
1360
1361class wxHtmlWinModule: public wxModule
1362{
1363DECLARE_DYNAMIC_CLASS(wxHtmlWinModule)
1364public:
1365 wxHtmlWinModule() : wxModule() {}
1366 bool OnInit() { return TRUE; }
1367 void OnExit() { wxHtmlWindow::CleanUpStatics(); }
1368};
1369
1370IMPLEMENT_DYNAMIC_CLASS(wxHtmlWinModule, wxModule)
1371
5526e819 1372
0cecad31
VS
1373// This hack forces the linker to always link in m_* files
1374// (wxHTML doesn't work without handlers from these files)
1375#include "wx/html/forcelnk.h"
1376FORCE_WXHTML_MODULES()
5526e819 1377
d659d703
VZ
1378#endif // wxUSE_HTML
1379