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