]> git.saurik.com Git - wxWidgets.git/blame - src/html/htmlwin.cpp
Move code that does not need realized GdkWinow out of realize handler
[wxWidgets.git] / src / html / htmlwin.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
93763ad5 2// Name: src/html/htmlwin.cpp
5526e819
VS
3// Purpose: wxHtmlWindow class for parsing & displaying HTML (implementation)
4// Author: Vaclav Slavik
5// Copyright: (c) 1999 Vaclav Slavik
65571936 6// Licence: wxWindows licence
5526e819
VS
7/////////////////////////////////////////////////////////////////////////////
8
3096bd2f 9#include "wx/wxprec.h"
5526e819 10
2b5f62a0 11#ifdef __BORLANDC__
93763ad5 12 #pragma hdrstop
5526e819
VS
13#endif
14
93763ad5
WS
15#if wxUSE_HTML && wxUSE_STREAMS
16
b4f4d3dd 17#ifndef WX_PRECOMP
8ecff181 18 #include "wx/list.h"
04dbb646
VZ
19 #include "wx/log.h"
20 #include "wx/intl.h"
21 #include "wx/dcclient.h"
22 #include "wx/frame.h"
f38924e8 23 #include "wx/dcmemory.h"
c0badb70 24 #include "wx/timer.h"
9eddec69 25 #include "wx/settings.h"
28f92d74 26 #include "wx/dataobj.h"
82a46104 27 #include "wx/statusbr.h"
5526e819
VS
28#endif
29
69941f05 30#include "wx/html/htmlwin.h"
892aeafc 31#include "wx/html/htmlproc.h"
e3774124 32#include "wx/clipbrd.h"
a7b2c092 33#include "wx/recguard.h"
04dbb646
VZ
34
35#include "wx/arrimpl.cpp"
892aeafc
VS
36#include "wx/listimpl.cpp"
37
03a187cc
VZ
38// uncomment this line to visually show the extent of the selection
39//#define DEBUG_HTML_SELECTION
40
a1c3cdc4
VS
41// HTML events:
42IMPLEMENT_DYNAMIC_CLASS(wxHtmlLinkEvent, wxCommandEvent)
43IMPLEMENT_DYNAMIC_CLASS(wxHtmlCellEvent, wxCommandEvent)
44
ce7fe42e
VZ
45wxDEFINE_EVENT( wxEVT_HTML_CELL_CLICKED, wxHtmlCellEvent );
46wxDEFINE_EVENT( wxEVT_HTML_CELL_HOVER, wxHtmlCellEvent );
47wxDEFINE_EVENT( wxEVT_HTML_LINK_CLICKED, wxHtmlLinkEvent );
a1c3cdc4 48
1338c59a 49
1338c59a
VS
50#if wxUSE_CLIPBOARD
51// ----------------------------------------------------------------------------
52// wxHtmlWinAutoScrollTimer: the timer used to generate a stream of scroll
53// events when a captured mouse is held outside the window
54// ----------------------------------------------------------------------------
55
56class wxHtmlWinAutoScrollTimer : public wxTimer
57{
58public:
59 wxHtmlWinAutoScrollTimer(wxScrolledWindow *win,
60 wxEventType eventTypeToSend,
61 int pos, int orient)
62 {
63 m_win = win;
64 m_eventType = eventTypeToSend;
65 m_pos = pos;
66 m_orient = orient;
67 }
68
69 virtual void Notify();
70
71private:
72 wxScrolledWindow *m_win;
73 wxEventType m_eventType;
74 int m_pos,
75 m_orient;
76
c0c133e1 77 wxDECLARE_NO_COPY_CLASS(wxHtmlWinAutoScrollTimer);
1338c59a
VS
78};
79
80void wxHtmlWinAutoScrollTimer::Notify()
81{
82 // only do all this as long as the window is capturing the mouse
83 if ( wxWindow::GetCapture() != m_win )
84 {
85 Stop();
86 }
87 else // we still capture the mouse, continue generating events
88 {
89 // first scroll the window if we are allowed to do it
90 wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
91 event1.SetEventObject(m_win);
92 if ( m_win->GetEventHandler()->ProcessEvent(event1) )
93 {
94 // and then send a pseudo mouse-move event to refresh the selection
95 wxMouseEvent event2(wxEVT_MOTION);
96 wxGetMousePosition(&event2.m_x, &event2.m_y);
97
98 // the mouse event coordinates should be client, not screen as
99 // returned by wxGetMousePosition
100 wxWindow *parentTop = m_win;
101 while ( parentTop->GetParent() )
102 parentTop = parentTop->GetParent();
103 wxPoint ptOrig = parentTop->GetPosition();
104 event2.m_x -= ptOrig.x;
105 event2.m_y -= ptOrig.y;
106
107 event2.SetEventObject(m_win);
108
109 // FIXME: we don't fill in the other members - ok?
110 m_win->GetEventHandler()->ProcessEvent(event2);
111 }
112 else // can't scroll further, stop
113 {
114 Stop();
115 }
116 }
117}
d659d703
VZ
118
119#endif // wxUSE_CLIPBOARD
1338c59a
VS
120
121
122
892aeafc
VS
123//-----------------------------------------------------------------------------
124// wxHtmlHistoryItem
125//-----------------------------------------------------------------------------
126
127// item of history list
4460b6c4 128class WXDLLIMPEXP_HTML wxHtmlHistoryItem
892aeafc
VS
129{
130public:
131 wxHtmlHistoryItem(const wxString& p, const wxString& a) {m_Page = p, m_Anchor = a, m_Pos = 0;}
132 int GetPos() const {return m_Pos;}
133 void SetPos(int p) {m_Pos = p;}
134 const wxString& GetPage() const {return m_Page;}
135 const wxString& GetAnchor() const {return m_Anchor;}
136
137private:
138 wxString m_Page;
139 wxString m_Anchor;
140 int m_Pos;
141};
5526e819 142
5526e819
VS
143
144//-----------------------------------------------------------------------------
892aeafc 145// our private arrays:
5526e819
VS
146//-----------------------------------------------------------------------------
147
892aeafc 148WX_DECLARE_OBJARRAY(wxHtmlHistoryItem, wxHtmlHistoryArray);
17a1ebd1 149WX_DEFINE_OBJARRAY(wxHtmlHistoryArray)
5526e819 150
892aeafc 151WX_DECLARE_LIST(wxHtmlProcessor, wxHtmlProcessorList);
17a1ebd1 152WX_DEFINE_LIST(wxHtmlProcessorList)
5526e819 153
bc55e31b
VS
154//-----------------------------------------------------------------------------
155// wxHtmlWindowMouseHelper
156//-----------------------------------------------------------------------------
157
158wxHtmlWindowMouseHelper::wxHtmlWindowMouseHelper(wxHtmlWindowInterface *iface)
159 : m_tmpMouseMoved(false),
160 m_tmpLastLink(NULL),
161 m_tmpLastCell(NULL),
162 m_interface(iface)
163{
164}
165
166void wxHtmlWindowMouseHelper::HandleMouseMoved()
167{
168 m_tmpMouseMoved = true;
169}
170
171bool wxHtmlWindowMouseHelper::HandleMouseClick(wxHtmlCell *rootCell,
172 const wxPoint& pos,
173 const wxMouseEvent& event)
174{
175 if (!rootCell)
176 return false;
177
178 wxHtmlCell *cell = rootCell->FindCellByPos(pos.x, pos.y);
179 // this check is needed because FindCellByPos returns terminal cell and
180 // containers may have empty borders -- in this case NULL will be
181 // returned
182 if (!cell)
183 return false;
184
185 // adjust the coordinates to be relative to this cell:
186 wxPoint relpos = pos - cell->GetAbsPos(rootCell);
187
188 return OnCellClicked(cell, relpos.x, relpos.y, event);
189}
190
191void wxHtmlWindowMouseHelper::HandleIdle(wxHtmlCell *rootCell,
192 const wxPoint& pos)
193{
194 wxHtmlCell *cell = rootCell ? rootCell->FindCellByPos(pos.x, pos.y) : NULL;
195
196 if (cell != m_tmpLastCell)
197 {
198 wxHtmlLinkInfo *lnk = NULL;
199 if (cell)
200 {
201 // adjust the coordinates to be relative to this cell:
202 wxPoint relpos = pos - cell->GetAbsPos(rootCell);
203 lnk = cell->GetLink(relpos.x, relpos.y);
204 }
205
206 wxCursor cur;
207 if (cell)
e24c4e12 208 cur = cell->GetMouseCursorAt(m_interface, pos);
bc55e31b 209 else
88a1b648
VS
210 cur = m_interface->GetHTMLCursor(
211 wxHtmlWindowInterface::HTMLCursor_Default);
212
bc55e31b
VS
213 m_interface->GetHTMLWindow()->SetCursor(cur);
214
215 if (lnk != m_tmpLastLink)
216 {
217 if (lnk)
218 m_interface->SetHTMLStatusText(lnk->GetHref());
219 else
220 m_interface->SetHTMLStatusText(wxEmptyString);
221
222 m_tmpLastLink = lnk;
223 }
224
225 m_tmpLastCell = cell;
226 }
227 else // mouse moved but stayed in the same cell
228 {
229 if ( cell )
230 {
e24c4e12
VZ
231 // A single cell can have different cursors for different positions,
232 // so update cursor for this case as well.
233 wxCursor cur = cell->GetMouseCursorAt(m_interface, pos);
234 m_interface->GetHTMLWindow()->SetCursor(cur);
235
bc55e31b
VS
236 OnCellMouseHover(cell, pos.x, pos.y);
237 }
238 }
239
240 m_tmpMouseMoved = false;
241}
242
243bool wxHtmlWindowMouseHelper::OnCellClicked(wxHtmlCell *cell,
244 wxCoord x, wxCoord y,
245 const wxMouseEvent& event)
246{
ce7fe42e 247 wxHtmlCellEvent ev(wxEVT_HTML_CELL_CLICKED,
a1c3cdc4
VS
248 m_interface->GetHTMLWindow()->GetId(),
249 cell, wxPoint(x,y), event);
250
251 if (!m_interface->GetHTMLWindow()->GetEventHandler()->ProcessEvent(ev))
252 {
253 // if the event wasn't handled, do the default processing here:
254
9a83f860 255 wxASSERT_MSG( cell, wxT("can't be called with NULL cell") );
a1c3cdc4
VS
256
257 cell->ProcessMouseClick(m_interface, ev.GetPoint(), ev.GetMouseEvent());
258 }
bc55e31b 259
a1c3cdc4
VS
260 // true if a link was clicked, false otherwise
261 return ev.GetLinkClicked();
bc55e31b
VS
262}
263
a1c3cdc4
VS
264void wxHtmlWindowMouseHelper::OnCellMouseHover(wxHtmlCell * cell,
265 wxCoord x,
266 wxCoord y)
bc55e31b 267{
ce7fe42e 268 wxHtmlCellEvent ev(wxEVT_HTML_CELL_HOVER,
a1c3cdc4
VS
269 m_interface->GetHTMLWindow()->GetId(),
270 cell, wxPoint(x,y), wxMouseEvent());
271 m_interface->GetHTMLWindow()->GetEventHandler()->ProcessEvent(ev);
bc55e31b
VS
272}
273
a1c3cdc4
VS
274
275
276
892aeafc
VS
277//-----------------------------------------------------------------------------
278// wxHtmlWindow
279//-----------------------------------------------------------------------------
5526e819 280
88a1b648
VS
281wxList wxHtmlWindow::m_Filters;
282wxHtmlFilter *wxHtmlWindow::m_DefaultFilter = NULL;
283wxHtmlProcessorList *wxHtmlWindow::m_GlobalProcessors = NULL;
284wxCursor *wxHtmlWindow::ms_cursorLink = NULL;
285wxCursor *wxHtmlWindow::ms_cursorText = NULL;
286
287void wxHtmlWindow::CleanUpStatics()
288{
289 wxDELETE(m_DefaultFilter);
290 WX_CLEAR_LIST(wxList, m_Filters);
291 if (m_GlobalProcessors)
292 WX_CLEAR_LIST(wxHtmlProcessorList, *m_GlobalProcessors);
293 wxDELETE(m_GlobalProcessors);
294 wxDELETE(ms_cursorLink);
295 wxDELETE(ms_cursorText);
296}
5526e819 297
4f417130 298void wxHtmlWindow::Init()
5526e819 299{
89de9af3 300 m_tmpCanDrawLocks = 0;
5526e819 301 m_FS = new wxFileSystem();
67a99992 302#if wxUSE_STATUSBAR
37146d33
VS
303 m_RelatedStatusBar = NULL;
304 m_RelatedStatusBarIndex = -1;
67a99992 305#endif // wxUSE_STATUSBAR
5526e819 306 m_RelatedFrame = NULL;
892aeafc 307 m_TitleFormat = wxT("%s");
d5db80c2 308 m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
5526e819
VS
309 m_Cell = NULL;
310 m_Parser = new wxHtmlWinParser(this);
4f9297b0 311 m_Parser->SetFS(m_FS);
5526e819 312 m_HistoryPos = -1;
d1da8872 313 m_HistoryOn = true;
892aeafc
VS
314 m_History = new wxHtmlHistoryArray;
315 m_Processors = NULL;
4f417130 316 SetBorders(10);
adf2eb2d
VS
317 m_selection = NULL;
318 m_makingSelection = false;
1338c59a
VS
319#if wxUSE_CLIPBOARD
320 m_timerAutoScroll = NULL;
6ce51985 321 m_lastDoubleClick = 0;
d659d703 322#endif // wxUSE_CLIPBOARD
b3c03420 323 m_tmpSelFromCell = NULL;
4f417130
VS
324}
325
790dbce3 326bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id,
4f417130 327 const wxPoint& pos, const wxSize& size,
790dbce3 328 long style, const wxString& name)
4f417130 329{
790dbce3 330 if (!wxScrolledWindow::Create(parent, id, pos, size,
2a536376
VS
331 style | wxVSCROLL | wxHSCROLL,
332 name))
d1da8872 333 return false;
4f417130 334
03a187cc
VZ
335 // We can't erase our background in EVT_ERASE_BACKGROUND handler and use
336 // double buffering in EVT_PAINT handler as this requires blitting back
337 // something already drawn on the window to the backing store bitmap when
338 // handling EVT_PAINT but blitting in this direction is simply not
339 // supported by OS X.
340 //
341 // So instead we use a hack with artificial EVT_ERASE_BACKGROUND generation
342 // from OnPaint() and this means that we never need the "real" erase event
343 // at all so disable it to avoid executing any user-defined handlers twice
344 // (and to avoid processing unnecessary event if no handlers are defined).
345 SetBackgroundStyle(wxBG_STYLE_PAINT);
4f9297b0 346 SetPage(wxT("<html><body></body></html>"));
8e494db9
JS
347
348 SetInitialSize(size);
d1da8872 349 return true;
5526e819
VS
350}
351
352
5526e819
VS
353wxHtmlWindow::~wxHtmlWindow()
354{
1338c59a
VS
355#if wxUSE_CLIPBOARD
356 StopAutoScrolling();
d659d703 357#endif // wxUSE_CLIPBOARD
5526e819
VS
358 HistoryClear();
359
689c4829
VZ
360 delete m_selection;
361
362 delete m_Cell;
5526e819 363
d80096a2
VZ
364 if ( m_Processors )
365 {
366 WX_CLEAR_LIST(wxHtmlProcessorList, *m_Processors);
367 }
222ed1d6 368
5526e819
VS
369 delete m_Parser;
370 delete m_FS;
892aeafc
VS
371 delete m_History;
372 delete m_Processors;
5526e819
VS
373}
374
375
376
377void wxHtmlWindow::SetRelatedFrame(wxFrame* frame, const wxString& format)
378{
379 m_RelatedFrame = frame;
380 m_TitleFormat = format;
381}
382
383
384
67a99992 385#if wxUSE_STATUSBAR
37146d33 386void wxHtmlWindow::SetRelatedStatusBar(int index)
5526e819 387{
37146d33 388 m_RelatedStatusBarIndex = index;
5526e819 389}
37146d33
VS
390
391void wxHtmlWindow::SetRelatedStatusBar(wxStatusBar* statusbar, int index)
392{
393 m_RelatedStatusBar = statusbar;
394 m_RelatedStatusBarIndex = index;
395}
396
67a99992 397#endif // wxUSE_STATUSBAR
269e8200
RD
398
399
400
fbfb8bcc 401void wxHtmlWindow::SetFonts(const wxString& normal_face, const wxString& fixed_face, const int *sizes)
5526e819 402{
4f9297b0 403 m_Parser->SetFonts(normal_face, fixed_face, sizes);
73de5077
VS
404
405 // re-layout the page after changing fonts:
406 DoSetPage(*(m_Parser->GetSource()));
5526e819
VS
407}
408
10e5c7ea
VS
409void wxHtmlWindow::SetStandardFonts(int size,
410 const wxString& normal_face,
411 const wxString& fixed_face)
7acd3625 412{
10e5c7ea 413 m_Parser->SetStandardFonts(size, normal_face, fixed_face);
5526e819 414
73de5077
VS
415 // re-layout the page after changing fonts:
416 DoSetPage(*(m_Parser->GetSource()));
417}
5526e819
VS
418
419bool wxHtmlWindow::SetPage(const wxString& source)
73de5077
VS
420{
421 m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
422 return DoSetPage(source);
423}
424
425bool wxHtmlWindow::DoSetPage(const wxString& source)
5526e819 426{
892aeafc
VS
427 wxString newsrc(source);
428
adf2eb2d
VS
429 wxDELETE(m_selection);
430
b3c03420
VS
431 // we will soon delete all the cells, so clear pointers to them:
432 m_tmpSelFromCell = NULL;
433
892aeafc 434 // pass HTML through registered processors:
960ba969 435 if (m_Processors || m_GlobalProcessors)
892aeafc 436 {
222ed1d6 437 wxHtmlProcessorList::compatibility_iterator nodeL, nodeG;
960ba969 438 int prL, prG;
892aeafc 439
0cc70962
VZ
440 if ( m_Processors )
441 nodeL = m_Processors->GetFirst();
442 if ( m_GlobalProcessors )
443 nodeG = m_GlobalProcessors->GetFirst();
960ba969
VS
444
445 // VS: there are two lists, global and local, both of them sorted by
e421922f 446 // priority. Since we have to go through _both_ lists with
960ba969
VS
447 // decreasing priority, we "merge-sort" the lists on-line by
448 // processing that one of the two heads that has higher priority
449 // in every iteration
450 while (nodeL || nodeG)
892aeafc
VS
451 {
452 prL = (nodeL) ? nodeL->GetData()->GetPriority() : -1;
960ba969
VS
453 prG = (nodeG) ? nodeG->GetData()->GetPriority() : -1;
454 if (prL > prG)
892aeafc 455 {
73348d09
VS
456 if (nodeL->GetData()->IsEnabled())
457 newsrc = nodeL->GetData()->Process(newsrc);
892aeafc
VS
458 nodeL = nodeL->GetNext();
459 }
960ba969 460 else // prL <= prG
892aeafc 461 {
73348d09
VS
462 if (nodeG->GetData()->IsEnabled())
463 newsrc = nodeG->GetData()->Process(newsrc);
960ba969 464 nodeG = nodeG->GetNext();
892aeafc
VS
465 }
466 }
467 }
5526e819 468
892aeafc
VS
469 // ...and run the parser on it:
470 wxClientDC *dc = new wxClientDC(this);
4f9297b0 471 dc->SetMapMode(wxMM_TEXT);
5526e819 472 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
97e490f8 473 SetBackgroundImage(wxNullBitmap);
73de5077 474
4f9297b0 475 m_Parser->SetDC(dc);
5276b0a5
VZ
476
477 // notice that it's important to set m_Cell to NULL here before calling
478 // Parse() below, even if it will be overwritten by its return value as
479 // without this we may crash if it's used from inside Parse(), so use
480 // wxDELETE() and not just delete here
481 wxDELETE(m_Cell);
482
892aeafc 483 m_Cell = (wxHtmlContainerCell*) m_Parser->Parse(newsrc);
5526e819 484 delete dc;
4f9297b0
VS
485 m_Cell->SetIndent(m_Borders, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
486 m_Cell->SetAlignHor(wxHTML_ALIGN_CENTER);
5526e819 487 CreateLayout();
bfb9ee96 488 if (m_tmpCanDrawLocks == 0)
892aeafc 489 Refresh();
d1da8872 490 return true;
5526e819
VS
491}
492
39029898
VS
493bool wxHtmlWindow::AppendToPage(const wxString& source)
494{
73de5077 495 return DoSetPage(*(GetParser()->GetSource()) + source);
39029898 496}
5526e819
VS
497
498bool wxHtmlWindow::LoadPage(const wxString& location)
499{
179a30e2
VZ
500 wxCHECK_MSG( !location.empty(), false, "location must be non-empty" );
501
1ccabb81 502 wxBusyCursor busyCursor;
790dbce3 503
5526e819 504 bool rt_val;
d1da8872 505 bool needs_refresh = false;
33ac7e6f 506
89de9af3 507 m_tmpCanDrawLocks++;
e421922f 508 if (m_HistoryOn && (m_HistoryPos != -1))
4f9297b0 509 {
960ba969 510 // store scroll position into history item:
5526e819 511 int x, y;
e421922f 512 GetViewStart(&x, &y);
892aeafc 513 (*m_History)[m_HistoryPos].SetPos(y);
5526e819
VS
514 }
515
e4e487e2
VZ
516 // first check if we're moving to an anchor in the same page
517 size_t posLocalAnchor = location.Find('#');
518 if ( posLocalAnchor != wxString::npos && posLocalAnchor != 0 )
4f9297b0 519 {
e4e487e2
VZ
520 // check if the part before the anchor is the same as the (either
521 // relative or absolute) URI of the current page
522 const wxString beforeAnchor = location.substr(0, posLocalAnchor);
523 if ( beforeAnchor != m_OpenedPage &&
524 m_FS->GetPath() + beforeAnchor != m_OpenedPage )
525 {
526 // indicate that we're not moving to a local anchor
527 posLocalAnchor = wxString::npos;
528 }
fc7dfaf8 529 }
e4e487e2
VZ
530
531 if ( posLocalAnchor != wxString::npos )
e421922f 532 {
fc7dfaf8 533 m_tmpCanDrawLocks--;
e4e487e2 534 rt_val = ScrollToAnchor(location.substr(posLocalAnchor + 1));
fc7dfaf8 535 m_tmpCanDrawLocks++;
5526e819 536 }
e4e487e2 537 else // moving to another page
4f9297b0 538 {
67a99992
WS
539 needs_refresh = true;
540#if wxUSE_STATUSBAR
5526e819 541 // load&display it:
37146d33 542 if (m_RelatedStatusBarIndex != -1)
e421922f 543 {
37146d33 544 SetHTMLStatusText(_("Connecting..."));
67a99992 545 Refresh(false);
5526e819 546 }
67a99992 547#endif // wxUSE_STATUSBAR
790dbce3 548
e4e487e2 549 wxFSFile *f = m_Parser->OpenURL(wxHTML_URL_PAGE, location);
33ac7e6f 550
7cb9cf89
VS
551 // try to interpret 'location' as filename instead of URL:
552 if (f == NULL)
553 {
554 wxFileName fn(location);
555 wxString location2 = wxFileSystem::FileNameToURL(fn);
556 f = m_Parser->OpenURL(wxHTML_URL_PAGE, location2);
557 }
558
33ac7e6f 559 if (f == NULL)
e421922f 560 {
f6bcfd97 561 wxLogError(_("Unable to open requested HTML document: %s"), location.c_str());
89de9af3 562 m_tmpCanDrawLocks--;
f1edd54c 563 SetHTMLStatusText(wxEmptyString);
67a99992 564 return false;
5526e819
VS
565 }
566
33ac7e6f 567 else
e421922f 568 {
222ed1d6 569 wxList::compatibility_iterator node;
5526e819
VS
570 wxString src = wxEmptyString;
571
67a99992 572#if wxUSE_STATUSBAR
37146d33 573 if (m_RelatedStatusBarIndex != -1)
e421922f 574 {
5526e819 575 wxString msg = _("Loading : ") + location;
37146d33 576 SetHTMLStatusText(msg);
67a99992 577 Refresh(false);
5526e819 578 }
67a99992 579#endif // wxUSE_STATUSBAR
5526e819
VS
580
581 node = m_Filters.GetFirst();
4f9297b0 582 while (node)
e421922f 583 {
4f9297b0
VS
584 wxHtmlFilter *h = (wxHtmlFilter*) node->GetData();
585 if (h->CanRead(*f))
e421922f 586 {
4f9297b0 587 src = h->ReadFile(*f);
5526e819
VS
588 break;
589 }
4f9297b0 590 node = node->GetNext();
5526e819 591 }
33ac7e6f 592 if (src == wxEmptyString)
e421922f 593 {
89de9af3 594 if (m_DefaultFilter == NULL) m_DefaultFilter = GetDefaultFilter();
4f9297b0 595 src = m_DefaultFilter->ReadFile(*f);
89de9af3 596 }
5526e819 597
4f9297b0 598 m_FS->ChangePathTo(f->GetLocation());
5526e819 599 rt_val = SetPage(src);
4f9297b0 600 m_OpenedPage = f->GetLocation();
33ac7e6f 601 if (f->GetAnchor() != wxEmptyString)
e421922f 602 {
4f9297b0 603 ScrollToAnchor(f->GetAnchor());
5526e819
VS
604 }
605
606 delete f;
607
67a99992 608#if wxUSE_STATUSBAR
37146d33
VS
609 if (m_RelatedStatusBarIndex != -1)
610 {
611 SetHTMLStatusText(_("Done"));
612 }
67a99992 613#endif // wxUSE_STATUSBAR
5526e819
VS
614 }
615 }
616
4f9297b0
VS
617 if (m_HistoryOn) // add this page to history there:
618 {
892aeafc 619 int c = m_History->GetCount() - (m_HistoryPos + 1);
5526e819 620
0cb9cfb2 621 if (m_HistoryPos < 0 ||
ee19c324
VS
622 (*m_History)[m_HistoryPos].GetPage() != m_OpenedPage ||
623 (*m_History)[m_HistoryPos].GetAnchor() != m_OpenedAnchor)
624 {
625 m_HistoryPos++;
626 for (int i = 0; i < c; i++)
b54e41c5 627 m_History->RemoveAt(m_HistoryPos);
ee19c324
VS
628 m_History->Add(new wxHtmlHistoryItem(m_OpenedPage, m_OpenedAnchor));
629 }
5526e819
VS
630 }
631
096824d7
VS
632 if (m_OpenedPageTitle == wxEmptyString)
633 OnSetTitle(wxFileNameFromPath(m_OpenedPage));
fc7dfaf8 634
33ac7e6f 635 if (needs_refresh)
4f9297b0 636 {
fc7dfaf8
VS
637 m_tmpCanDrawLocks--;
638 Refresh();
639 }
640 else
641 m_tmpCanDrawLocks--;
642
5526e819
VS
643 return rt_val;
644}
645
646
7cb9cf89
VS
647bool wxHtmlWindow::LoadFile(const wxFileName& filename)
648{
649 wxString url = wxFileSystem::FileNameToURL(filename);
650 return LoadPage(url);
651}
652
5526e819
VS
653
654bool wxHtmlWindow::ScrollToAnchor(const wxString& anchor)
655{
4f9297b0 656 const wxHtmlCell *c = m_Cell->Find(wxHTML_COND_ISANCHOR, &anchor);
f3c82859
VS
657 if (!c)
658 {
f6bcfd97 659 wxLogWarning(_("HTML anchor %s does not exist."), anchor.c_str());
d1da8872 660 return false;
f3c82859 661 }
33ac7e6f 662 else
4f9297b0 663 {
8e6c2840
VS
664 // Go to next visible cell in current container, if it exists. This
665 // yields a bit better (even though still imperfect) results in that
666 // there's better chance of using a suitable cell for upper Y
667 // coordinate value. See bug #11406 for additional discussion.
668 const wxHtmlCell *c_save = c;
669 while ( c && c->IsFormattingCell() )
670 c = c->GetNext();
671 if ( !c )
672 c = c_save;
673
5526e819 674 int y;
269e8200 675
4f9297b0 676 for (y = 0; c != NULL; c = c->GetParent()) y += c->GetPosY();
efba2b89 677 Scroll(-1, y / wxHTML_SCROLL_STEP);
5526e819 678 m_OpenedAnchor = anchor;
d1da8872 679 return true;
5526e819
VS
680 }
681}
682
683
d5db80c2 684void wxHtmlWindow::OnSetTitle(const wxString& title)
5526e819 685{
33ac7e6f 686 if (m_RelatedFrame)
4f9297b0 687 {
5526e819
VS
688 wxString tit;
689 tit.Printf(m_TitleFormat, title.c_str());
4f9297b0 690 m_RelatedFrame->SetTitle(tit);
5526e819 691 }
d5db80c2 692 m_OpenedPageTitle = title;
5526e819
VS
693}
694
695
a7b2c092
VS
696// return scroll steps such that a) scrollbars aren't shown needlessly
697// and b) entire content is viewable (i.e. round up)
698static int ScrollSteps(int size, int available)
699{
700 if ( size <= available )
701 return 0;
702 else
703 return (size + wxHTML_SCROLL_STEP - 1) / wxHTML_SCROLL_STEP;
704}
5526e819
VS
705
706
707void wxHtmlWindow::CreateLayout()
708{
a7b2c092
VS
709 // SetScrollbars() results in size change events -- and thus a nested
710 // CreateLayout() call -- on some platforms. Ignore nested calls, toplevel
711 // CreateLayout() will do the right thing eventually.
712 static wxRecursionGuardFlag s_flagReentrancy;
713 wxRecursionGuard guard(s_flagReentrancy);
714 if ( guard.IsInside() )
715 return;
716
717 if (!m_Cell)
718 return;
5526e819 719
a7b2c092
VS
720 int clientWidth, clientHeight;
721 GetClientSize(&clientWidth, &clientHeight);
722
723 const int vscrollbar = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
724 const int hscrollbar = wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
725
726 if ( HasScrollbar(wxHORIZONTAL) )
727 clientHeight += hscrollbar;
728
729 if ( HasScrollbar(wxVERTICAL) )
730 clientWidth += vscrollbar;
a547ebff 731
cc87fbed 732 if ( HasFlag(wxHW_SCROLLBAR_NEVER) )
4f9297b0 733 {
689f42f4 734 SetScrollbars(1, 1, 0, 0); // always off
a7b2c092 735 m_Cell->Layout(clientWidth);
a547ebff 736 }
cc87fbed
VZ
737 else // !wxHW_SCROLLBAR_NEVER
738 {
a7b2c092
VS
739 // Lay the content out with the assumption that it's too large to fit
740 // in the window (this is likely to be the case):
741 m_Cell->Layout(clientWidth - vscrollbar);
742
743 // If the layout is wider than the window, horizontal scrollbar will
744 // certainly be shown. Account for it here for subsequent computations.
745 if ( m_Cell->GetWidth() > clientWidth )
746 clientHeight -= hscrollbar;
747
748 if ( m_Cell->GetHeight() <= clientHeight )
e421922f 749 {
a7b2c092
VS
750 // we fit into the window, hide vertical scrollbar:
751 SetScrollbars
752 (
753 wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
754 ScrollSteps(m_Cell->GetWidth(), clientWidth - vscrollbar),
755 0
756 );
757 // ...and redo the layout to use the extra space
758 m_Cell->Layout(clientWidth);
a547ebff 759 }
a7b2c092 760 else
e421922f 761 {
a7b2c092
VS
762 // If the content doesn't fit into the window by only a small
763 // margin, chances are that it may fit fully with scrollbar turned
764 // off. It's something worth trying but on the other hand, we don't
765 // want to waste too much time redoing the layout (twice!) for
766 // long -- and thus expensive to layout -- pages. The cut-off value
767 // is an arbitrary heuristics.
768 static const int SMALL_OVERLAP = 60;
769 if ( m_Cell->GetHeight() <= clientHeight + SMALL_OVERLAP )
770 {
771 m_Cell->Layout(clientWidth);
772
773 if ( m_Cell->GetHeight() <= clientHeight )
774 {
775 // Great, we fit in. Hide the scrollbar.
776 SetScrollbars
777 (
778 wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
779 ScrollSteps(m_Cell->GetWidth(), clientWidth),
780 0
781 );
782 return;
783 }
784 else
785 {
786 // That didn't work out, go back to previous layout. Note
787 // that redoing the layout once again here isn't as bad as
788 // it looks -- thanks to the small cut-off value, it's a
789 // reasonably small page.
790 m_Cell->Layout(clientWidth - vscrollbar);
791 }
792 }
793 // else: the page is very long, it will certainly need scrollbar
794
795 SetScrollbars
796 (
797 wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
798 ScrollSteps(m_Cell->GetWidth(), clientWidth - vscrollbar),
799 ScrollSteps(m_Cell->GetHeight(), clientHeight)
800 );
89de9af3 801 }
a547ebff 802 }
5526e819
VS
803}
804
b4246849 805#if wxUSE_CONFIG
5526e819
VS
806void wxHtmlWindow::ReadCustomization(wxConfigBase *cfg, wxString path)
807{
808 wxString oldpath;
809 wxString tmp;
d5db80c2
VS
810 int p_fontsizes[7];
811 wxString p_fff, p_ffn;
5526e819 812
33ac7e6f 813 if (path != wxEmptyString)
4f9297b0
VS
814 {
815 oldpath = cfg->GetPath();
816 cfg->SetPath(path);
5526e819
VS
817 }
818
892aeafc
VS
819 m_Borders = cfg->Read(wxT("wxHtmlWindow/Borders"), m_Borders);
820 p_fff = cfg->Read(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser->m_FontFaceFixed);
821 p_ffn = cfg->Read(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser->m_FontFaceNormal);
bfb9ee96 822 for (int i = 0; i < 7; i++)
4f9297b0 823 {
66a77a74 824 tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
4f9297b0 825 p_fontsizes[i] = cfg->Read(tmp, m_Parser->m_FontsSizes[i]);
5526e819 826 }
8eb2940f 827 SetFonts(p_ffn, p_fff, p_fontsizes);
5526e819
VS
828
829 if (path != wxEmptyString)
4f9297b0 830 cfg->SetPath(oldpath);
5526e819
VS
831}
832
833
834
835void wxHtmlWindow::WriteCustomization(wxConfigBase *cfg, wxString path)
836{
837 wxString oldpath;
838 wxString tmp;
839
33ac7e6f 840 if (path != wxEmptyString)
4f9297b0
VS
841 {
842 oldpath = cfg->GetPath();
843 cfg->SetPath(path);
5526e819
VS
844 }
845
892aeafc
VS
846 cfg->Write(wxT("wxHtmlWindow/Borders"), (long) m_Borders);
847 cfg->Write(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser->m_FontFaceFixed);
848 cfg->Write(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser->m_FontFaceNormal);
bfb9ee96 849 for (int i = 0; i < 7; i++)
4f9297b0 850 {
66a77a74 851 tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
4f9297b0 852 cfg->Write(tmp, (long) m_Parser->m_FontsSizes[i]);
5526e819
VS
853 }
854
855 if (path != wxEmptyString)
4f9297b0 856 cfg->SetPath(oldpath);
5526e819 857}
b4246849 858#endif // wxUSE_CONFIG
5526e819
VS
859
860bool wxHtmlWindow::HistoryBack()
861{
862 wxString a, l;
863
d1da8872 864 if (m_HistoryPos < 1) return false;
5526e819 865
bbda1088
VS
866 // store scroll position into history item:
867 int x, y;
e421922f 868 GetViewStart(&x, &y);
892aeafc 869 (*m_History)[m_HistoryPos].SetPos(y);
bbda1088
VS
870
871 // go to previous position:
5526e819
VS
872 m_HistoryPos--;
873
892aeafc
VS
874 l = (*m_History)[m_HistoryPos].GetPage();
875 a = (*m_History)[m_HistoryPos].GetAnchor();
d1da8872 876 m_HistoryOn = false;
89de9af3 877 m_tmpCanDrawLocks++;
5526e819 878 if (a == wxEmptyString) LoadPage(l);
fc7dfaf8 879 else LoadPage(l + wxT("#") + a);
d1da8872 880 m_HistoryOn = true;
89de9af3 881 m_tmpCanDrawLocks--;
892aeafc 882 Scroll(0, (*m_History)[m_HistoryPos].GetPos());
5526e819 883 Refresh();
d1da8872 884 return true;
5526e819
VS
885}
886
1b113a81
VS
887bool wxHtmlWindow::HistoryCanBack()
888{
d1da8872
WS
889 if (m_HistoryPos < 1) return false;
890 return true ;
1b113a81 891}
5526e819
VS
892
893
894bool wxHtmlWindow::HistoryForward()
895{
896 wxString a, l;
897
d1da8872
WS
898 if (m_HistoryPos == -1) return false;
899 if (m_HistoryPos >= (int)m_History->GetCount() - 1)return false;
5526e819
VS
900
901 m_OpenedPage = wxEmptyString; // this will disable adding new entry into history in LoadPage()
902
903 m_HistoryPos++;
892aeafc
VS
904 l = (*m_History)[m_HistoryPos].GetPage();
905 a = (*m_History)[m_HistoryPos].GetAnchor();
d1da8872 906 m_HistoryOn = false;
89de9af3 907 m_tmpCanDrawLocks++;
5526e819 908 if (a == wxEmptyString) LoadPage(l);
fc7dfaf8 909 else LoadPage(l + wxT("#") + a);
d1da8872 910 m_HistoryOn = true;
89de9af3 911 m_tmpCanDrawLocks--;
892aeafc 912 Scroll(0, (*m_History)[m_HistoryPos].GetPos());
5526e819 913 Refresh();
d1da8872 914 return true;
5526e819
VS
915}
916
1b113a81
VS
917bool wxHtmlWindow::HistoryCanForward()
918{
d1da8872
WS
919 if (m_HistoryPos == -1) return false;
920 if (m_HistoryPos >= (int)m_History->GetCount() - 1)return false;
921 return true ;
1b113a81 922}
5526e819
VS
923
924
925void wxHtmlWindow::HistoryClear()
926{
892aeafc 927 m_History->Empty();
5526e819
VS
928 m_HistoryPos = -1;
929}
930
892aeafc
VS
931void wxHtmlWindow::AddProcessor(wxHtmlProcessor *processor)
932{
933 if (!m_Processors)
934 {
935 m_Processors = new wxHtmlProcessorList;
892aeafc 936 }
222ed1d6 937 wxHtmlProcessorList::compatibility_iterator node;
bfb9ee96 938
892aeafc
VS
939 for (node = m_Processors->GetFirst(); node; node = node->GetNext())
940 {
bfb9ee96 941 if (processor->GetPriority() > node->GetData()->GetPriority())
892aeafc
VS
942 {
943 m_Processors->Insert(node, processor);
960ba969 944 return;
892aeafc
VS
945 }
946 }
960ba969 947 m_Processors->Append(processor);
892aeafc
VS
948}
949
960ba969 950/*static */ void wxHtmlWindow::AddGlobalProcessor(wxHtmlProcessor *processor)
892aeafc 951{
960ba969 952 if (!m_GlobalProcessors)
892aeafc 953 {
960ba969 954 m_GlobalProcessors = new wxHtmlProcessorList;
892aeafc 955 }
222ed1d6 956 wxHtmlProcessorList::compatibility_iterator node;
e421922f 957
960ba969 958 for (node = m_GlobalProcessors->GetFirst(); node; node = node->GetNext())
892aeafc 959 {
bfb9ee96 960 if (processor->GetPriority() > node->GetData()->GetPriority())
892aeafc 961 {
960ba969
VS
962 m_GlobalProcessors->Insert(node, processor);
963 return;
892aeafc
VS
964 }
965 }
960ba969 966 m_GlobalProcessors->Append(processor);
892aeafc
VS
967}
968
5526e819
VS
969
970
5526e819
VS
971void wxHtmlWindow::AddFilter(wxHtmlFilter *filter)
972{
5526e819
VS
973 m_Filters.Append(filter);
974}
975
976
36c4ff4d
VS
977bool wxHtmlWindow::IsSelectionEnabled() const
978{
979#if wxUSE_CLIPBOARD
cc87fbed 980 return !HasFlag(wxHW_NO_SELECTION);
36c4ff4d
VS
981#else
982 return false;
983#endif
984}
d659d703 985
e3774124 986
1338c59a 987#if wxUSE_CLIPBOARD
977b867e 988wxString wxHtmlWindow::DoSelectionToText(wxHtmlSelection *sel)
e3774124 989{
977b867e 990 if ( !sel )
e3774124
VS
991 return wxEmptyString;
992
f30e67db 993 wxClientDC dc(this);
e3774124 994 wxString text;
7f8f381c
VS
995
996 wxHtmlTerminalCellsInterator i(sel->GetFromCell(), sel->GetToCell());
997 const wxHtmlCell *prev = NULL;
998
e3774124
VS
999 while ( i )
1000 {
7f8f381c
VS
1001 // When converting HTML content to plain text, the entire paragraph
1002 // (container in wxHTML) goes on single line. A new paragraph (that
1003 // should go on its own line) has its own container. Therefore, the
1004 // simplest way of detecting where to insert newlines in plain text
1005 // is to check if the parent container changed -- if it did, we moved
1006 // to a new paragraph.
1007 if ( prev && prev->GetParent() != i->GetParent() )
1008 text << '\n';
1009
1010 // NB: we don't need to pass the selection to ConvertToText() in the
1011 // middle of the selected text; it's only useful when only part of
1012 // a cell is selected
1013 text << i->ConvertToText(sel);
1014
e3774124
VS
1015 prev = *i;
1016 ++i;
1017 }
1018 return text;
1019}
1020
977b867e
VS
1021wxString wxHtmlWindow::ToText()
1022{
1023 if (m_Cell)
1024 {
1025 wxHtmlSelection sel;
1026 sel.Set(m_Cell->GetFirstTerminal(), m_Cell->GetLastTerminal());
1027 return DoSelectionToText(&sel);
1028 }
1029 else
1030 return wxEmptyString;
1031}
1032
d659d703
VZ
1033#endif // wxUSE_CLIPBOARD
1034
8feaa81f 1035bool wxHtmlWindow::CopySelection(ClipboardType t)
e3774124 1036{
d659d703 1037#if wxUSE_CLIPBOARD
e3774124
VS
1038 if ( m_selection )
1039 {
28b2ac5b 1040#if defined(__UNIX__) && !defined(__WXMAC__)
e3774124 1041 wxTheClipboard->UsePrimarySelection(t == Primary);
d659d703
VZ
1042#else // !__UNIX__
1043 // Primary selection exists only under X11, so don't do anything under
1044 // the other platforms when we try to access it
1045 //
1046 // TODO: this should be abstracted at wxClipboard level!
1047 if ( t == Primary )
8feaa81f 1048 return false;
d659d703
VZ
1049#endif // __UNIX__/!__UNIX__
1050
e3774124
VS
1051 if ( wxTheClipboard->Open() )
1052 {
d659d703 1053 const wxString txt(SelectionToText());
e3774124
VS
1054 wxTheClipboard->SetData(new wxTextDataObject(txt));
1055 wxTheClipboard->Close();
9a83f860 1056 wxLogTrace(wxT("wxhtmlselection"),
e3774124 1057 _("Copied to clipboard:\"%s\""), txt.c_str());
8feaa81f
VZ
1058
1059 return true;
e3774124
VS
1060 }
1061 }
caf448e3
WS
1062#else
1063 wxUnusedVar(t);
d659d703 1064#endif // wxUSE_CLIPBOARD
8feaa81f
VZ
1065
1066 return false;
e3774124 1067}
5526e819
VS
1068
1069
0b2dadd3 1070void wxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link)
5526e819 1071{
a1c3cdc4 1072 wxHtmlLinkEvent event(GetId(), link);
33c2a4b7 1073 event.SetEventObject(this);
a1c3cdc4
VS
1074 if (!GetEventHandler()->ProcessEvent(event))
1075 {
1076 // the default behaviour is to load the URL in this window
1077 const wxMouseEvent *e = event.GetLinkInfo().GetEvent();
1078 if (e == NULL || e->LeftUp())
1079 LoadPage(event.GetLinkInfo().GetHref());
1080 }
5526e819
VS
1081}
1082
03a187cc 1083void wxHtmlWindow::DoEraseBackground(wxDC& dc)
1338c59a 1084{
03a187cc
VZ
1085 // if we don't have any background bitmap we just fill it with background
1086 // colour and we also must do it if the background bitmap is not fully
1087 // opaque as otherwise junk could be left there
1088 if ( !m_bmpBg.IsOk() || m_bmpBg.GetMask() )
97e490f8 1089 {
03a187cc 1090 dc.SetBackground(GetBackgroundColour());
97e490f8
VZ
1091 dc.Clear();
1092 }
1093
03a187cc 1094 if ( m_bmpBg.IsOk() )
97e490f8 1095 {
03a187cc 1096 // draw the background bitmap tiling it over the entire window area
4340a145 1097 const wxSize sz = GetVirtualSize();
03a187cc
VZ
1098 const wxSize sizeBmp(m_bmpBg.GetWidth(), m_bmpBg.GetHeight());
1099 for ( wxCoord x = 0; x < sz.x; x += sizeBmp.x )
97e490f8 1100 {
03a187cc
VZ
1101 for ( wxCoord y = 0; y < sz.y; y += sizeBmp.y )
1102 {
1103 dc.DrawBitmap(m_bmpBg, x, y, true /* use mask */);
1104 }
97e490f8
VZ
1105 }
1106 }
1338c59a
VS
1107}
1108
49b489e8
VZ
1109void wxHtmlWindow::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
1110{
1111 // We never get real erase background events as we changed our background
1112 // style to wxBG_STYLE_PAINT in our ctor so the only time when we get here
1113 // is when an artificial wxEraseEvent is generated by our own OnPaint()
1114 // below. This handler only exists to stop the event from propagating
1115 // downwards to wxWindow which may erase the background itself when it gets
1116 // it in some ports (currently this happens in wxUniv), so we simply stop
1117 // processing here and set a special flag allowing OnPaint() to see that
1118 // the event hadn't been really processed.
1119 m_isBgReallyErased = false;
1120}
1121
1338c59a 1122void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
5526e819 1123{
03a187cc 1124 wxPaintDC dcPaint(this);
1338c59a 1125
518ba663
VZ
1126 if (m_tmpCanDrawLocks > 0 || m_Cell == NULL)
1127 return;
5526e819 1128
b835e9bf 1129 int x, y;
e421922f 1130 GetViewStart(&x, &y);
03a187cc
VZ
1131 const wxRect rect = GetUpdateRegion().GetBox();
1132 const wxSize sz = GetClientSize();
1133
1134 // set up the DC we're drawing on: if the window is already double buffered
1135 // we do it directly on wxPaintDC, otherwise we allocate a backing store
1136 // buffer and compose the drawing there and then blit it to screen all at
1137 // once
1138 wxDC *dc;
1338c59a 1139 wxMemoryDC dcm;
03a187cc 1140 if ( IsDoubleBuffered() )
518ba663 1141 {
03a187cc
VZ
1142 dc = &dcPaint;
1143 }
1144 else // window is not double buffered by the system, do it ourselves
1145 {
1146 if ( !m_backBuffer.IsOk() )
1147 m_backBuffer.Create(sz.x, sz.y);
1148 dcm.SelectObject(m_backBuffer);
1149 dc = &dcm;
518ba663 1150 }
03a187cc
VZ
1151
1152 PrepareDC(*dc);
1153
49b489e8
VZ
1154 // Erase the background: for compatibility, we must generate the event to
1155 // allow the user-defined handlers to do it, hence this hack with sending
1156 // an artificial wxEraseEvent to trigger the execution of such handlers.
03a187cc
VZ
1157 wxEraseEvent eraseEvent(GetId(), dc);
1158 eraseEvent.SetEventObject(this);
49b489e8
VZ
1159
1160 // Hack inside a hack: the background wasn't really erased if our own
1161 // OnEraseBackground() was executed, so we need to check for the flag set
1162 // by it whenever it's called.
1163 m_isBgReallyErased = true; // Initially assume it wasn't.
1164 if ( !ProcessWindowEvent(eraseEvent) || !m_isBgReallyErased )
518ba663 1165 {
03a187cc
VZ
1166 // erase background ourselves
1167 DoEraseBackground(*dc);
518ba663 1168 }
03a187cc 1169 //else: background erased by the user-defined handler
a03ae172 1170
03a187cc
VZ
1171
1172 // draw the HTML window contents
1173 dc->SetMapMode(wxMM_TEXT);
3ee9771b 1174 dc->SetBackgroundMode(wxTRANSPARENT);
88ed20a2 1175 dc->SetLayoutDirection(GetLayoutDirection());
d659d703 1176
f30e67db
VS
1177 wxHtmlRenderingInfo rinfo;
1178 wxDefaultHtmlRenderingStyle rstyle;
1179 rinfo.SetSelection(m_selection);
1180 rinfo.SetStyle(&rstyle);
03a187cc 1181 m_Cell->Draw(*dc, 0, 0,
790dbce3 1182 y * wxHTML_SCROLL_STEP + rect.GetTop(),
36c4ff4d 1183 y * wxHTML_SCROLL_STEP + rect.GetBottom(),
f30e67db 1184 rinfo);
d1da8872 1185
03693319
VS
1186#ifdef DEBUG_HTML_SELECTION
1187 {
1188 int xc, yc, x, y;
1189 wxGetMousePosition(&xc, &yc);
1190 ScreenToClient(&xc, &yc);
1191 CalcUnscrolledPosition(xc, yc, &x, &y);
1192 wxHtmlCell *at = m_Cell->FindCellByPos(x, y);
d1da8872 1193 wxHtmlCell *before =
03693319 1194 m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_BEFORE);
d1da8872 1195 wxHtmlCell *after =
03693319 1196 m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_AFTER);
d1da8872 1197
03a187cc
VZ
1198 dc->SetBrush(*wxTRANSPARENT_BRUSH);
1199 dc->SetPen(*wxBLACK_PEN);
03693319 1200 if (at)
03a187cc 1201 dc->DrawRectangle(at->GetAbsPos(),
03693319 1202 wxSize(at->GetWidth(),at->GetHeight()));
03a187cc 1203 dc->SetPen(*wxGREEN_PEN);
03693319 1204 if (before)
03a187cc 1205 dc->DrawRectangle(before->GetAbsPos().x+1, before->GetAbsPos().y+1,
03693319 1206 before->GetWidth()-2,before->GetHeight()-2);
03a187cc 1207 dc->SetPen(*wxRED_PEN);
03693319 1208 if (after)
03a187cc 1209 dc->DrawRectangle(after->GetAbsPos().x+2, after->GetAbsPos().y+2,
03693319
VS
1210 after->GetWidth()-4,after->GetHeight()-4);
1211 }
03a187cc 1212#endif // DEBUG_HTML_SELECTION
d1da8872 1213
03a187cc
VZ
1214 if ( dc != &dcPaint )
1215 {
1216 dc->SetDeviceOrigin(0,0);
1217 dcPaint.Blit(0, rect.GetTop(),
1218 sz.x, rect.GetBottom() - rect.GetTop() + 1,
1219 dc,
1220 0, rect.GetTop());
1221 }
5526e819
VS
1222}
1223
1224
1225
1226
1227void wxHtmlWindow::OnSize(wxSizeEvent& event)
1228{
6528a7f1
VZ
1229 event.Skip();
1230
03a187cc 1231 m_backBuffer = wxNullBitmap;
1338c59a 1232
5526e819 1233 CreateLayout();
1338c59a
VS
1234
1235 // Recompute selection if necessary:
1236 if ( m_selection )
1237 {
1238 m_selection->Set(m_selection->GetFromCell(),
1239 m_selection->GetToCell());
2f0bebe6 1240 m_selection->ClearFromToCharacterPos();
1338c59a 1241 }
d659d703 1242
f6bcfd97 1243 Refresh();
5526e819
VS
1244}
1245
1246
fc7a2a60 1247void wxHtmlWindow::OnMouseMove(wxMouseEvent& WXUNUSED(event))
5526e819 1248{
bc55e31b 1249 wxHtmlWindowMouseHelper::HandleMouseMoved();
31d8b4ad 1250}
5526e819 1251
adf2eb2d 1252void wxHtmlWindow::OnMouseDown(wxMouseEvent& event)
31d8b4ad 1253{
0994d968 1254#if wxUSE_CLIPBOARD
adf2eb2d 1255 if ( event.LeftDown() && IsSelectionEnabled() )
4f9297b0 1256 {
0994d968
VS
1257 const long TRIPLECLICK_LEN = 200; // 0.2 sec after doubleclick
1258 if ( wxGetLocalTimeMillis() - m_lastDoubleClick <= TRIPLECLICK_LEN )
adf2eb2d 1259 {
0994d968 1260 SelectLine(CalcUnscrolledPosition(event.GetPosition()));
d659d703 1261
5de65c69 1262 (void) CopySelection();
adf2eb2d 1263 }
0994d968 1264 else
d659d703 1265 {
0994d968 1266 m_makingSelection = true;
d659d703 1267
0994d968
VS
1268 if ( m_selection )
1269 {
1270 wxDELETE(m_selection);
1271 Refresh();
1272 }
1273 m_tmpSelFromPos = CalcUnscrolledPosition(event.GetPosition());
1274 m_tmpSelFromCell = NULL;
5526e819 1275
0994d968
VS
1276 CaptureMouse();
1277 }
adf2eb2d 1278 }
d659d703 1279#endif // wxUSE_CLIPBOARD
bc0e68eb
VZ
1280
1281 // in any case, let the default handler set focus to this window
1282 event.Skip();
adf2eb2d 1283}
5526e819 1284
adf2eb2d
VS
1285void wxHtmlWindow::OnMouseUp(wxMouseEvent& event)
1286{
1338c59a 1287#if wxUSE_CLIPBOARD
adf2eb2d
VS
1288 if ( m_makingSelection )
1289 {
1290 ReleaseMouse();
1291 m_makingSelection = false;
1292
907f2fab
VS
1293 // if m_selection=NULL, the user didn't move the mouse far enough from
1294 // starting point and the mouse up event is part of a click, the user
1295 // is not selecting text:
1296 if ( m_selection )
adf2eb2d 1297 {
907f2fab
VS
1298 CopySelection(Primary);
1299
adf2eb2d
VS
1300 // we don't want mouse up event that ended selecting to be
1301 // handled as mouse click and e.g. follow hyperlink:
1302 return;
1303 }
1304 }
d659d703
VZ
1305#endif // wxUSE_CLIPBOARD
1306
bc55e31b 1307 wxPoint pos = CalcUnscrolledPosition(event.GetPosition());
615f68c6
VZ
1308 if ( !wxHtmlWindowMouseHelper::HandleMouseClick(m_Cell, pos, event) )
1309 event.Skip();
5526e819
VS
1310}
1311
63e819f2
VS
1312#if wxUSE_CLIPBOARD
1313void wxHtmlWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
1314{
1315 if ( !m_makingSelection )
1316 return;
1317
1318 // discard the selecting operation
1319 m_makingSelection = false;
1320 wxDELETE(m_selection);
1321 m_tmpSelFromCell = NULL;
1322 Refresh();
1323}
1324#endif // wxUSE_CLIPBOARD
5526e819
VS
1325
1326
5180055b
JS
1327void wxHtmlWindow::OnInternalIdle()
1328{
1329 wxWindow::OnInternalIdle();
d1da8872 1330
bc55e31b 1331 if (m_Cell != NULL && DidMouseMove())
4f9297b0 1332 {
03693319
VS
1333#ifdef DEBUG_HTML_SELECTION
1334 Refresh();
1335#endif
adf2eb2d
VS
1336 int xc, yc, x, y;
1337 wxGetMousePosition(&xc, &yc);
1338 ScreenToClient(&xc, &yc);
1339 CalcUnscrolledPosition(xc, yc, &x, &y);
0cb9cfb2 1340
f6010d8f 1341 wxHtmlCell *cell = m_Cell->FindCellByPos(x, y);
adf2eb2d
VS
1342
1343 // handle selection update:
1344 if ( m_makingSelection )
1345 {
adf2eb2d 1346 if ( !m_tmpSelFromCell )
748418c0
VS
1347 m_tmpSelFromCell = m_Cell->FindCellByPos(
1348 m_tmpSelFromPos.x,m_tmpSelFromPos.y);
d1da8872 1349
03693319
VS
1350 // NB: a trick - we adjust selFromPos to be upper left or bottom
1351 // right corner of the first cell of the selection depending
1352 // on whether the mouse is moving to the right or to the left.
1353 // This gives us more "natural" behaviour when selecting
1354 // a line (specifically, first cell of the next line is not
1355 // included if you drag selection from left to right over
1356 // entire line):
1357 wxPoint dirFromPos;
1358 if ( !m_tmpSelFromCell )
1359 {
1360 dirFromPos = m_tmpSelFromPos;
1361 }
1362 else
1363 {
1364 dirFromPos = m_tmpSelFromCell->GetAbsPos();
1365 if ( x < m_tmpSelFromPos.x )
1366 {
1367 dirFromPos.x += m_tmpSelFromCell->GetWidth();
1368 dirFromPos.y += m_tmpSelFromCell->GetHeight();
1369 }
1370 }
d1da8872 1371 bool goingDown = dirFromPos.y < y ||
03693319
VS
1372 (dirFromPos.y == y && dirFromPos.x < x);
1373
1374 // determine selection span:
748418c0 1375 if ( /*still*/ !m_tmpSelFromCell )
adf2eb2d
VS
1376 {
1377 if (goingDown)
1378 {
5a1597e9
VS
1379 m_tmpSelFromCell = m_Cell->FindCellByPos(
1380 m_tmpSelFromPos.x,m_tmpSelFromPos.y,
1381 wxHTML_FIND_NEAREST_AFTER);
adf2eb2d
VS
1382 if (!m_tmpSelFromCell)
1383 m_tmpSelFromCell = m_Cell->GetFirstTerminal();
1384 }
1385 else
1386 {
5a1597e9
VS
1387 m_tmpSelFromCell = m_Cell->FindCellByPos(
1388 m_tmpSelFromPos.x,m_tmpSelFromPos.y,
1389 wxHTML_FIND_NEAREST_BEFORE);
adf2eb2d
VS
1390 if (!m_tmpSelFromCell)
1391 m_tmpSelFromCell = m_Cell->GetLastTerminal();
1392 }
1393 }
1394
1395 wxHtmlCell *selcell = cell;
1396 if (!selcell)
1397 {
1398 if (goingDown)
1399 {
1400 selcell = m_Cell->FindCellByPos(x, y,
03693319 1401 wxHTML_FIND_NEAREST_BEFORE);
adf2eb2d
VS
1402 if (!selcell)
1403 selcell = m_Cell->GetLastTerminal();
1404 }
1405 else
1406 {
1407 selcell = m_Cell->FindCellByPos(x, y,
03693319 1408 wxHTML_FIND_NEAREST_AFTER);
adf2eb2d
VS
1409 if (!selcell)
1410 selcell = m_Cell->GetFirstTerminal();
1411 }
1412 }
1413
1414 // NB: it may *rarely* happen that the code above didn't find one
1415 // of the cells, e.g. if wxHtmlWindow doesn't contain any
d659d703 1416 // visible cells.
adf2eb2d 1417 if ( selcell && m_tmpSelFromCell )
d659d703 1418 {
adf2eb2d
VS
1419 if ( !m_selection )
1420 {
1421 // start selecting only if mouse movement was big enough
1422 // (otherwise it was meant as mouse click, not selection):
1423 const int PRECISION = 2;
1424 wxPoint diff = m_tmpSelFromPos - wxPoint(x,y);
1425 if (abs(diff.x) > PRECISION || abs(diff.y) > PRECISION)
1426 {
1427 m_selection = new wxHtmlSelection();
1428 }
1429 }
1430 if ( m_selection )
1431 {
e3774124 1432 if ( m_tmpSelFromCell->IsBefore(selcell) )
adf2eb2d
VS
1433 {
1434 m_selection->Set(m_tmpSelFromPos, m_tmpSelFromCell,
a1c3cdc4
VS
1435 wxPoint(x,y), selcell);
1436 }
adf2eb2d
VS
1437 else
1438 {
1439 m_selection->Set(wxPoint(x,y), selcell,
1440 m_tmpSelFromPos, m_tmpSelFromCell);
1441 }
2f0bebe6 1442 m_selection->ClearFromToCharacterPos();
1338c59a 1443 Refresh();
adf2eb2d
VS
1444 }
1445 }
1446 }
d659d703 1447
adf2eb2d 1448 // handle cursor and status bar text changes:
f6010d8f 1449
bc55e31b
VS
1450 // NB: because we're passing in 'cell' and not 'm_Cell' (so that the
1451 // leaf cell lookup isn't done twice), we need to adjust the
1452 // position for the new root:
1453 wxPoint posInCell(x, y);
1454 if (cell)
1455 posInCell -= cell->GetAbsPos();
1456 wxHtmlWindowMouseHelper::HandleIdle(cell, posInCell);
5526e819
VS
1457 }
1458}
1459
e3774124 1460#if wxUSE_CLIPBOARD
1338c59a
VS
1461void wxHtmlWindow::StopAutoScrolling()
1462{
1463 if ( m_timerAutoScroll )
1464 {
1465 wxDELETE(m_timerAutoScroll);
1466 }
1467}
1468
1469void wxHtmlWindow::OnMouseEnter(wxMouseEvent& event)
1470{
1471 StopAutoScrolling();
1472 event.Skip();
1473}
1474
1475void wxHtmlWindow::OnMouseLeave(wxMouseEvent& event)
1476{
1477 // don't prevent the usual processing of the event from taking place
1478 event.Skip();
1479
1480 // when a captured mouse leave a scrolled window we start generate
1481 // scrolling events to allow, for example, extending selection beyond the
1482 // visible area in some controls
1483 if ( wxWindow::GetCapture() == this )
1484 {
1485 // where is the mouse leaving?
1486 int pos, orient;
1487 wxPoint pt = event.GetPosition();
1488 if ( pt.x < 0 )
1489 {
1490 orient = wxHORIZONTAL;
1491 pos = 0;
1492 }
1493 else if ( pt.y < 0 )
1494 {
1495 orient = wxVERTICAL;
1496 pos = 0;
1497 }
1498 else // we're lower or to the right of the window
1499 {
1500 wxSize size = GetClientSize();
1501 if ( pt.x > size.x )
1502 {
1503 orient = wxHORIZONTAL;
1504 pos = GetVirtualSize().x / wxHTML_SCROLL_STEP;
1505 }
1506 else if ( pt.y > size.y )
1507 {
1508 orient = wxVERTICAL;
1509 pos = GetVirtualSize().y / wxHTML_SCROLL_STEP;
1510 }
1511 else // this should be impossible
1512 {
1513 // but seems to happen sometimes under wxMSW - maybe it's a bug
1514 // there but for now just ignore it
1515
9a83f860 1516 //wxFAIL_MSG( wxT("can't understand where has mouse gone") );
1338c59a
VS
1517
1518 return;
1519 }
1520 }
1521
1522 // only start the auto scroll timer if the window can be scrolled in
1523 // this direction
1524 if ( !HasScrollbar(orient) )
1525 return;
1526
1527 delete m_timerAutoScroll;
1528 m_timerAutoScroll = new wxHtmlWinAutoScrollTimer
1529 (
1530 this,
1531 pos == 0 ? wxEVT_SCROLLWIN_LINEUP
1532 : wxEVT_SCROLLWIN_LINEDOWN,
1533 pos,
1534 orient
1535 );
1536 m_timerAutoScroll->Start(50); // FIXME: make configurable
1537 }
1538}
1539
e3774124
VS
1540void wxHtmlWindow::OnKeyUp(wxKeyEvent& event)
1541{
0f11c233
VZ
1542 if ( IsSelectionEnabled() &&
1543 (event.GetKeyCode() == 'C' && event.CmdDown()) )
e3774124 1544 {
ce7fe42e 1545 wxClipboardTextEvent evt(wxEVT_TEXT_COPY, GetId());
0f11c233
VZ
1546
1547 evt.SetEventObject(this);
1548
1549 GetEventHandler()->ProcessEvent(evt);
e3774124 1550 }
fca74306
VS
1551 else
1552 {
1553 event.Skip();
1554 }
e3774124
VS
1555}
1556
fc7a2a60 1557void wxHtmlWindow::OnCopy(wxCommandEvent& WXUNUSED(event))
e3774124 1558{
5de65c69 1559 (void) CopySelection();
e3774124 1560}
d659d703 1561
0f11c233
VZ
1562void wxHtmlWindow::OnClipboardEvent(wxClipboardTextEvent& WXUNUSED(event))
1563{
1564 (void) CopySelection();
1565}
1566
31eefb99
VS
1567void wxHtmlWindow::OnDoubleClick(wxMouseEvent& event)
1568{
1569 // select word under cursor:
1570 if ( IsSelectionEnabled() )
1571 {
0994d968 1572 SelectWord(CalcUnscrolledPosition(event.GetPosition()));
d659d703 1573
5de65c69 1574 (void) CopySelection(Primary);
d659d703 1575
0994d968 1576 m_lastDoubleClick = wxGetLocalTimeMillis();
31eefb99
VS
1577 }
1578 else
1579 event.Skip();
1580}
0994d968
VS
1581
1582void wxHtmlWindow::SelectWord(const wxPoint& pos)
1583{
2a536376 1584 if ( m_Cell )
0994d968 1585 {
2a536376
VS
1586 wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
1587 if ( cell )
1588 {
1589 delete m_selection;
1590 m_selection = new wxHtmlSelection();
1591 m_selection->Set(cell, cell);
1592 RefreshRect(wxRect(CalcScrolledPosition(cell->GetAbsPos()),
1593 wxSize(cell->GetWidth(), cell->GetHeight())));
1594 }
0994d968
VS
1595 }
1596}
1597
1598void wxHtmlWindow::SelectLine(const wxPoint& pos)
1599{
2a536376 1600 if ( m_Cell )
0994d968 1601 {
2a536376
VS
1602 wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
1603 if ( cell )
0994d968 1604 {
2a536376
VS
1605 // We use following heuristic to find a "line": let the line be all
1606 // cells in same container as the cell under mouse cursor that are
4c51a665 1607 // neither completely above nor completely below the clicked cell
2a536376
VS
1608 // (i.e. are likely to be words positioned on same line of text).
1609
1610 int y1 = cell->GetAbsPos().y;
1611 int y2 = y1 + cell->GetHeight();
1612 int y;
1613 const wxHtmlCell *c;
1614 const wxHtmlCell *before = NULL;
1615 const wxHtmlCell *after = NULL;
1616
1617 // find last cell of line:
1618 for ( c = cell->GetNext(); c; c = c->GetNext())
1619 {
1620 y = c->GetAbsPos().y;
1621 if ( y + c->GetHeight() > y1 && y < y2 )
1622 after = c;
1623 else
1624 break;
1625 }
1626 if ( !after )
1627 after = cell;
0994d968 1628
2a536376
VS
1629 // find first cell of line:
1630 for ( c = cell->GetParent()->GetFirstChild();
1631 c && c != cell; c = c->GetNext())
0994d968 1632 {
2a536376
VS
1633 y = c->GetAbsPos().y;
1634 if ( y + c->GetHeight() > y1 && y < y2 )
1635 {
1636 if ( ! before )
1637 before = c;
1638 }
1639 else
1640 before = NULL;
0994d968 1641 }
2a536376
VS
1642 if ( !before )
1643 before = cell;
1644
1645 delete m_selection;
1646 m_selection = new wxHtmlSelection();
1647 m_selection->Set(before, after);
1648
1649 Refresh();
0994d968 1650 }
2a536376
VS
1651 }
1652}
d659d703 1653
2a536376
VS
1654void wxHtmlWindow::SelectAll()
1655{
1656 if ( m_Cell )
1657 {
0994d968
VS
1658 delete m_selection;
1659 m_selection = new wxHtmlSelection();
2a536376 1660 m_selection->Set(m_Cell->GetFirstTerminal(), m_Cell->GetLastTerminal());
0994d968
VS
1661 Refresh();
1662 }
1663}
2a536376 1664
d659d703 1665#endif // wxUSE_CLIPBOARD
e3774124
VS
1666
1667
5526e819 1668
bfb9ee96 1669IMPLEMENT_ABSTRACT_CLASS(wxHtmlProcessor,wxObject)
5526e819 1670
459f2add 1671wxBEGIN_PROPERTIES_TABLE(wxHtmlWindow)
786a2425 1672/*
d1da8872
WS
1673 TODO PROPERTIES
1674 style , wxHW_SCROLLBAR_AUTO
1675 borders , (dimension)
1676 url , string
1677 htmlcode , string
786a2425 1678*/
459f2add 1679wxEND_PROPERTIES_TABLE()
786a2425 1680
459f2add
SC
1681wxBEGIN_HANDLERS_TABLE(wxHtmlWindow)
1682wxEND_HANDLERS_TABLE()
786a2425 1683
d1da8872 1684wxCONSTRUCTOR_5( wxHtmlWindow , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
28953245
SC
1685
1686wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxHtmlWindow, wxScrolledWindow,"wx/html/htmlwin.h")
5526e819
VS
1687
1688BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
1689 EVT_SIZE(wxHtmlWindow::OnSize)
adf2eb2d
VS
1690 EVT_LEFT_DOWN(wxHtmlWindow::OnMouseDown)
1691 EVT_LEFT_UP(wxHtmlWindow::OnMouseUp)
1692 EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp)
31d8b4ad 1693 EVT_MOTION(wxHtmlWindow::OnMouseMove)
1338c59a 1694 EVT_PAINT(wxHtmlWindow::OnPaint)
49b489e8 1695 EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground)
e3774124 1696#if wxUSE_CLIPBOARD
31eefb99 1697 EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick)
1338c59a
VS
1698 EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter)
1699 EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave)
63e819f2 1700 EVT_MOUSE_CAPTURE_LOST(wxHtmlWindow::OnMouseCaptureLost)
e3774124
VS
1701 EVT_KEY_UP(wxHtmlWindow::OnKeyUp)
1702 EVT_MENU(wxID_COPY, wxHtmlWindow::OnCopy)
0f11c233 1703 EVT_TEXT_COPY(wxID_ANY, wxHtmlWindow::OnClipboardEvent)
d659d703 1704#endif // wxUSE_CLIPBOARD
5526e819
VS
1705END_EVENT_TABLE()
1706
bc55e31b
VS
1707//-----------------------------------------------------------------------------
1708// wxHtmlWindowInterface implementation in wxHtmlWindow
1709//-----------------------------------------------------------------------------
1710
1711void wxHtmlWindow::SetHTMLWindowTitle(const wxString& title)
1712{
1713 OnSetTitle(title);
1714}
1715
1716void wxHtmlWindow::OnHTMLLinkClicked(const wxHtmlLinkInfo& link)
1717{
1718 OnLinkClicked(link);
1719}
1720
1721wxHtmlOpeningStatus wxHtmlWindow::OnHTMLOpeningURL(wxHtmlURLType type,
1722 const wxString& url,
1723 wxString *redirect) const
1724{
1725 return OnOpeningURL(type, url, redirect);
1726}
1727
1728wxPoint wxHtmlWindow::HTMLCoordsToWindow(wxHtmlCell *WXUNUSED(cell),
1729 const wxPoint& pos) const
1730{
1731 return CalcScrolledPosition(pos);
1732}
1733
1734wxWindow* wxHtmlWindow::GetHTMLWindow()
1735{
1736 return this;
1737}
1738
1739wxColour wxHtmlWindow::GetHTMLBackgroundColour() const
1740{
1741 return GetBackgroundColour();
1742}
1743
1744void wxHtmlWindow::SetHTMLBackgroundColour(const wxColour& clr)
1745{
1746 SetBackgroundColour(clr);
1747}
1748
1749void wxHtmlWindow::SetHTMLBackgroundImage(const wxBitmap& bmpBg)
1750{
1751 SetBackgroundImage(bmpBg);
1752}
5526e819 1753
bc55e31b
VS
1754void wxHtmlWindow::SetHTMLStatusText(const wxString& text)
1755{
1756#if wxUSE_STATUSBAR
37146d33
VS
1757 if (m_RelatedStatusBarIndex != -1)
1758 {
1759 if (m_RelatedStatusBar)
1760 {
1761 m_RelatedStatusBar->SetStatusText(text, m_RelatedStatusBarIndex);
1762 }
1763 else if (m_RelatedFrame)
1764 {
1765 m_RelatedFrame->SetStatusText(text, m_RelatedStatusBarIndex);
1766 }
1767 }
80d99525
WS
1768#else
1769 wxUnusedVar(text);
bc55e31b
VS
1770#endif // wxUSE_STATUSBAR
1771}
5526e819 1772
88a1b648
VS
1773/*static*/
1774wxCursor wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor type)
1775{
1776 switch (type)
1777 {
1778 case HTMLCursor_Link:
1779 if ( !ms_cursorLink )
1780 ms_cursorLink = new wxCursor(wxCURSOR_HAND);
1781 return *ms_cursorLink;
1782
1783 case HTMLCursor_Text:
1784 if ( !ms_cursorText )
1785 ms_cursorText = new wxCursor(wxCURSOR_IBEAM);
1786 return *ms_cursorText;
1787
1788 case HTMLCursor_Default:
1789 default:
1790 return *wxSTANDARD_CURSOR;
1791 }
1792}
1793
1794wxCursor wxHtmlWindow::GetHTMLCursor(HTMLCursor type) const
1795{
1796 return GetDefaultHTMLCursor(type);
1797}
1798
5526e819 1799
bc55e31b
VS
1800//-----------------------------------------------------------------------------
1801// wxHtmlWinModule
1802//-----------------------------------------------------------------------------
5526e819 1803
a76015e6
VS
1804// A module to allow initialization/cleanup
1805// without calling these functions from app.cpp or from
1806// the user's application.
1807
1808class wxHtmlWinModule: public wxModule
1809{
1810DECLARE_DYNAMIC_CLASS(wxHtmlWinModule)
1811public:
1812 wxHtmlWinModule() : wxModule() {}
d1da8872 1813 bool OnInit() { return true; }
a76015e6
VS
1814 void OnExit() { wxHtmlWindow::CleanUpStatics(); }
1815};
1816
1817IMPLEMENT_DYNAMIC_CLASS(wxHtmlWinModule, wxModule)
1818
5526e819 1819
0cecad31
VS
1820// This hack forces the linker to always link in m_* files
1821// (wxHTML doesn't work without handlers from these files)
1822#include "wx/html/forcelnk.h"
1823FORCE_WXHTML_MODULES()
5526e819 1824
d659d703 1825#endif // wxUSE_HTML