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