]> git.saurik.com Git - wxWidgets.git/blame - src/html/htmlwin.cpp
make sure we are feeding coordinates of HIView instances, not wx-dimensions back...
[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
69941f05 5// RCS-ID: $Id$
5526e819 6// Copyright: (c) 1999 Vaclav Slavik
65571936 7// Licence: wxWindows licence
5526e819
VS
8/////////////////////////////////////////////////////////////////////////////
9
3096bd2f 10#include "wx/wxprec.h"
5526e819 11
2b5f62a0 12#ifdef __BORLANDC__
93763ad5 13 #pragma hdrstop
5526e819
VS
14#endif
15
93763ad5
WS
16#if wxUSE_HTML && wxUSE_STREAMS
17
5526e819 18#ifndef WXPRECOMP
8ecff181 19 #include "wx/list.h"
04dbb646
VZ
20 #include "wx/log.h"
21 #include "wx/intl.h"
22 #include "wx/dcclient.h"
23 #include "wx/frame.h"
f38924e8 24 #include "wx/dcmemory.h"
c0badb70 25 #include "wx/timer.h"
9eddec69 26 #include "wx/settings.h"
28f92d74 27 #include "wx/dataobj.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"
04dbb646
VZ
33
34#include "wx/arrimpl.cpp"
892aeafc
VS
35#include "wx/listimpl.cpp"
36
1338c59a 37
1338c59a
VS
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
44class wxHtmlWinAutoScrollTimer : public wxTimer
45{
46public:
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
59private:
60 wxScrolledWindow *m_win;
61 wxEventType m_eventType;
62 int m_pos,
63 m_orient;
64
65 DECLARE_NO_COPY_CLASS(wxHtmlWinAutoScrollTimer)
66};
67
68void 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}
d659d703
VZ
106
107#endif // wxUSE_CLIPBOARD
1338c59a
VS
108
109
110
892aeafc
VS
111//-----------------------------------------------------------------------------
112// wxHtmlHistoryItem
113//-----------------------------------------------------------------------------
114
115// item of history list
4460b6c4 116class WXDLLIMPEXP_HTML wxHtmlHistoryItem
892aeafc
VS
117{
118public:
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
125private:
126 wxString m_Page;
127 wxString m_Anchor;
128 int m_Pos;
129};
5526e819 130
5526e819
VS
131
132//-----------------------------------------------------------------------------
892aeafc 133// our private arrays:
5526e819
VS
134//-----------------------------------------------------------------------------
135
892aeafc 136WX_DECLARE_OBJARRAY(wxHtmlHistoryItem, wxHtmlHistoryArray);
17a1ebd1 137WX_DEFINE_OBJARRAY(wxHtmlHistoryArray)
5526e819 138
892aeafc 139WX_DECLARE_LIST(wxHtmlProcessor, wxHtmlProcessorList);
17a1ebd1 140WX_DEFINE_LIST(wxHtmlProcessorList)
5526e819 141
bc55e31b
VS
142//-----------------------------------------------------------------------------
143// wxHtmlWindowMouseHelper
144//-----------------------------------------------------------------------------
145
146wxHtmlWindowMouseHelper::wxHtmlWindowMouseHelper(wxHtmlWindowInterface *iface)
147 : m_tmpMouseMoved(false),
148 m_tmpLastLink(NULL),
149 m_tmpLastCell(NULL),
150 m_interface(iface)
151{
152}
153
154void wxHtmlWindowMouseHelper::HandleMouseMoved()
155{
156 m_tmpMouseMoved = true;
157}
158
159bool 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
179void 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)
88a1b648 196 cur = cell->GetMouseCursor(m_interface);
bc55e31b 197 else
88a1b648
VS
198 cur = m_interface->GetHTMLCursor(
199 wxHtmlWindowInterface::HTMLCursor_Default);
200
bc55e31b
VS
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
226bool 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
235void wxHtmlWindowMouseHelper::OnCellMouseHover(wxHtmlCell * WXUNUSED(cell),
236 wxCoord WXUNUSED(x),
237 wxCoord WXUNUSED(y))
238{
239 // do nothing here
240}
241
892aeafc
VS
242//-----------------------------------------------------------------------------
243// wxHtmlWindow
244//-----------------------------------------------------------------------------
5526e819 245
88a1b648
VS
246wxList wxHtmlWindow::m_Filters;
247wxHtmlFilter *wxHtmlWindow::m_DefaultFilter = NULL;
248wxHtmlProcessorList *wxHtmlWindow::m_GlobalProcessors = NULL;
249wxCursor *wxHtmlWindow::ms_cursorLink = NULL;
250wxCursor *wxHtmlWindow::ms_cursorText = NULL;
251
252void 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}
5526e819 262
4f417130 263void wxHtmlWindow::Init()
5526e819 264{
89de9af3 265 m_tmpCanDrawLocks = 0;
5526e819 266 m_FS = new wxFileSystem();
67a99992 267#if wxUSE_STATUSBAR
5526e819 268 m_RelatedStatusBar = -1;
67a99992 269#endif // wxUSE_STATUSBAR
5526e819 270 m_RelatedFrame = NULL;
892aeafc 271 m_TitleFormat = wxT("%s");
d5db80c2 272 m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
5526e819
VS
273 m_Cell = NULL;
274 m_Parser = new wxHtmlWinParser(this);
4f9297b0 275 m_Parser->SetFS(m_FS);
5526e819 276 m_HistoryPos = -1;
d1da8872 277 m_HistoryOn = true;
892aeafc
VS
278 m_History = new wxHtmlHistoryArray;
279 m_Processors = NULL;
4f417130 280 SetBorders(10);
adf2eb2d
VS
281 m_selection = NULL;
282 m_makingSelection = false;
1338c59a
VS
283#if wxUSE_CLIPBOARD
284 m_timerAutoScroll = NULL;
6ce51985 285 m_lastDoubleClick = 0;
d659d703 286#endif // wxUSE_CLIPBOARD
1338c59a 287 m_backBuffer = NULL;
518ba663 288 m_eraseBgInOnPaint = false;
b3c03420 289 m_tmpSelFromCell = NULL;
4f417130
VS
290}
291
790dbce3 292bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id,
4f417130 293 const wxPoint& pos, const wxSize& size,
790dbce3 294 long style, const wxString& name)
4f417130 295{
790dbce3 296 if (!wxScrolledWindow::Create(parent, id, pos, size,
2a536376
VS
297 style | wxVSCROLL | wxHSCROLL,
298 name))
d1da8872 299 return false;
4f417130 300
4f9297b0 301 SetPage(wxT("<html><body></body></html>"));
d1da8872 302 return true;
5526e819
VS
303}
304
305
5526e819
VS
306wxHtmlWindow::~wxHtmlWindow()
307{
1338c59a
VS
308#if wxUSE_CLIPBOARD
309 StopAutoScrolling();
d659d703 310#endif // wxUSE_CLIPBOARD
5526e819
VS
311 HistoryClear();
312
689c4829
VZ
313 delete m_selection;
314
315 delete m_Cell;
5526e819 316
d80096a2
VZ
317 if ( m_Processors )
318 {
319 WX_CLEAR_LIST(wxHtmlProcessorList, *m_Processors);
320 }
222ed1d6 321
5526e819
VS
322 delete m_Parser;
323 delete m_FS;
892aeafc
VS
324 delete m_History;
325 delete m_Processors;
1338c59a 326 delete m_backBuffer;
5526e819
VS
327}
328
329
330
331void wxHtmlWindow::SetRelatedFrame(wxFrame* frame, const wxString& format)
332{
333 m_RelatedFrame = frame;
334 m_TitleFormat = format;
335}
336
337
338
67a99992 339#if wxUSE_STATUSBAR
5526e819
VS
340void wxHtmlWindow::SetRelatedStatusBar(int bar)
341{
342 m_RelatedStatusBar = bar;
343}
67a99992 344#endif // wxUSE_STATUSBAR
269e8200
RD
345
346
347
fbfb8bcc 348void wxHtmlWindow::SetFonts(const wxString& normal_face, const wxString& fixed_face, const int *sizes)
5526e819 349{
4f9297b0 350 m_Parser->SetFonts(normal_face, fixed_face, sizes);
73de5077
VS
351
352 // re-layout the page after changing fonts:
353 DoSetPage(*(m_Parser->GetSource()));
5526e819
VS
354}
355
10e5c7ea
VS
356void wxHtmlWindow::SetStandardFonts(int size,
357 const wxString& normal_face,
358 const wxString& fixed_face)
7acd3625 359{
10e5c7ea 360 m_Parser->SetStandardFonts(size, normal_face, fixed_face);
5526e819 361
73de5077
VS
362 // re-layout the page after changing fonts:
363 DoSetPage(*(m_Parser->GetSource()));
364}
5526e819
VS
365
366bool wxHtmlWindow::SetPage(const wxString& source)
73de5077
VS
367{
368 m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
369 return DoSetPage(source);
370}
371
372bool wxHtmlWindow::DoSetPage(const wxString& source)
5526e819 373{
892aeafc
VS
374 wxString newsrc(source);
375
adf2eb2d
VS
376 wxDELETE(m_selection);
377
b3c03420
VS
378 // we will soon delete all the cells, so clear pointers to them:
379 m_tmpSelFromCell = NULL;
380
892aeafc 381 // pass HTML through registered processors:
960ba969 382 if (m_Processors || m_GlobalProcessors)
892aeafc 383 {
222ed1d6 384 wxHtmlProcessorList::compatibility_iterator nodeL, nodeG;
960ba969 385 int prL, prG;
892aeafc 386
0cc70962
VZ
387 if ( m_Processors )
388 nodeL = m_Processors->GetFirst();
389 if ( m_GlobalProcessors )
390 nodeG = m_GlobalProcessors->GetFirst();
960ba969
VS
391
392 // VS: there are two lists, global and local, both of them sorted by
e421922f 393 // priority. Since we have to go through _both_ lists with
960ba969
VS
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)
892aeafc
VS
398 {
399 prL = (nodeL) ? nodeL->GetData()->GetPriority() : -1;
960ba969
VS
400 prG = (nodeG) ? nodeG->GetData()->GetPriority() : -1;
401 if (prL > prG)
892aeafc 402 {
73348d09
VS
403 if (nodeL->GetData()->IsEnabled())
404 newsrc = nodeL->GetData()->Process(newsrc);
892aeafc
VS
405 nodeL = nodeL->GetNext();
406 }
960ba969 407 else // prL <= prG
892aeafc 408 {
73348d09
VS
409 if (nodeG->GetData()->IsEnabled())
410 newsrc = nodeG->GetData()->Process(newsrc);
960ba969 411 nodeG = nodeG->GetNext();
892aeafc
VS
412 }
413 }
414 }
5526e819 415
892aeafc
VS
416 // ...and run the parser on it:
417 wxClientDC *dc = new wxClientDC(this);
4f9297b0 418 dc->SetMapMode(wxMM_TEXT);
5526e819 419 SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
97e490f8 420 SetBackgroundImage(wxNullBitmap);
73de5077 421
4f9297b0 422 m_Parser->SetDC(dc);
33ac7e6f 423 if (m_Cell)
4f9297b0 424 {
89de9af3
VS
425 delete m_Cell;
426 m_Cell = NULL;
f61815af 427 }
892aeafc 428 m_Cell = (wxHtmlContainerCell*) m_Parser->Parse(newsrc);
5526e819 429 delete dc;
4f9297b0
VS
430 m_Cell->SetIndent(m_Borders, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
431 m_Cell->SetAlignHor(wxHTML_ALIGN_CENTER);
5526e819 432 CreateLayout();
bfb9ee96 433 if (m_tmpCanDrawLocks == 0)
892aeafc 434 Refresh();
d1da8872 435 return true;
5526e819
VS
436}
437
39029898
VS
438bool wxHtmlWindow::AppendToPage(const wxString& source)
439{
73de5077 440 return DoSetPage(*(GetParser()->GetSource()) + source);
39029898 441}
5526e819
VS
442
443bool wxHtmlWindow::LoadPage(const wxString& location)
444{
1ccabb81 445 wxBusyCursor busyCursor;
790dbce3 446
5526e819
VS
447 wxFSFile *f;
448 bool rt_val;
d1da8872 449 bool needs_refresh = false;
33ac7e6f 450
89de9af3 451 m_tmpCanDrawLocks++;
e421922f 452 if (m_HistoryOn && (m_HistoryPos != -1))
4f9297b0 453 {
960ba969 454 // store scroll position into history item:
5526e819 455 int x, y;
e421922f 456 GetViewStart(&x, &y);
892aeafc 457 (*m_History)[m_HistoryPos].SetPos(y);
5526e819
VS
458 }
459
e421922f 460 if (location[0] == wxT('#'))
4f9297b0 461 {
960ba969 462 // local anchor:
5526e819 463 wxString anch = location.Mid(1) /*1 to end*/;
89de9af3 464 m_tmpCanDrawLocks--;
5526e819 465 rt_val = ScrollToAnchor(anch);
fc7dfaf8
VS
466 m_tmpCanDrawLocks++;
467 }
33ac7e6f 468 else if (location.Find(wxT('#')) != wxNOT_FOUND && location.BeforeFirst(wxT('#')) == m_OpenedPage)
4f9297b0 469 {
fc7dfaf8
VS
470 wxString anch = location.AfterFirst(wxT('#'));
471 m_tmpCanDrawLocks--;
472 rt_val = ScrollToAnchor(anch);
473 m_tmpCanDrawLocks++;
474 }
33ac7e6f
KB
475 else if (location.Find(wxT('#')) != wxNOT_FOUND &&
476 (m_FS->GetPath() + location.BeforeFirst(wxT('#'))) == m_OpenedPage)
e421922f 477 {
fc7dfaf8
VS
478 wxString anch = location.AfterFirst(wxT('#'));
479 m_tmpCanDrawLocks--;
480 rt_val = ScrollToAnchor(anch);
481 m_tmpCanDrawLocks++;
5526e819
VS
482 }
483
33ac7e6f 484 else
4f9297b0 485 {
67a99992
WS
486 needs_refresh = true;
487#if wxUSE_STATUSBAR
5526e819 488 // load&display it:
33ac7e6f 489 if (m_RelatedStatusBar != -1)
e421922f 490 {
4f9297b0 491 m_RelatedFrame->SetStatusText(_("Connecting..."), m_RelatedStatusBar);
67a99992 492 Refresh(false);
5526e819 493 }
67a99992 494#endif // wxUSE_STATUSBAR
790dbce3 495
6cc4e6b8 496 f = m_Parser->OpenURL(wxHTML_URL_PAGE, location);
33ac7e6f 497
7cb9cf89
VS
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
33ac7e6f 506 if (f == NULL)
e421922f 507 {
f6bcfd97 508 wxLogError(_("Unable to open requested HTML document: %s"), location.c_str());
89de9af3 509 m_tmpCanDrawLocks--;
67a99992 510 return false;
5526e819
VS
511 }
512
33ac7e6f 513 else
e421922f 514 {
222ed1d6 515 wxList::compatibility_iterator node;
5526e819
VS
516 wxString src = wxEmptyString;
517
67a99992 518#if wxUSE_STATUSBAR
33ac7e6f 519 if (m_RelatedStatusBar != -1)
e421922f 520 {
5526e819 521 wxString msg = _("Loading : ") + location;
4f9297b0 522 m_RelatedFrame->SetStatusText(msg, m_RelatedStatusBar);
67a99992 523 Refresh(false);
5526e819 524 }
67a99992 525#endif // wxUSE_STATUSBAR
5526e819
VS
526
527 node = m_Filters.GetFirst();
4f9297b0 528 while (node)
e421922f 529 {
4f9297b0
VS
530 wxHtmlFilter *h = (wxHtmlFilter*) node->GetData();
531 if (h->CanRead(*f))
e421922f 532 {
4f9297b0 533 src = h->ReadFile(*f);
5526e819
VS
534 break;
535 }
4f9297b0 536 node = node->GetNext();
5526e819 537 }
33ac7e6f 538 if (src == wxEmptyString)
e421922f 539 {
89de9af3 540 if (m_DefaultFilter == NULL) m_DefaultFilter = GetDefaultFilter();
4f9297b0 541 src = m_DefaultFilter->ReadFile(*f);
89de9af3 542 }
5526e819 543
4f9297b0 544 m_FS->ChangePathTo(f->GetLocation());
5526e819 545 rt_val = SetPage(src);
4f9297b0 546 m_OpenedPage = f->GetLocation();
33ac7e6f 547 if (f->GetAnchor() != wxEmptyString)
e421922f 548 {
4f9297b0 549 ScrollToAnchor(f->GetAnchor());
5526e819
VS
550 }
551
552 delete f;
553
67a99992 554#if wxUSE_STATUSBAR
d1da8872 555 if (m_RelatedStatusBar != -1)
67a99992
WS
556 m_RelatedFrame->SetStatusText(_("Done"), m_RelatedStatusBar);
557#endif // wxUSE_STATUSBAR
5526e819
VS
558 }
559 }
560
4f9297b0
VS
561 if (m_HistoryOn) // add this page to history there:
562 {
892aeafc 563 int c = m_History->GetCount() - (m_HistoryPos + 1);
5526e819 564
0cb9cfb2 565 if (m_HistoryPos < 0 ||
ee19c324
VS
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++)
b54e41c5 571 m_History->RemoveAt(m_HistoryPos);
ee19c324
VS
572 m_History->Add(new wxHtmlHistoryItem(m_OpenedPage, m_OpenedAnchor));
573 }
5526e819
VS
574 }
575
096824d7
VS
576 if (m_OpenedPageTitle == wxEmptyString)
577 OnSetTitle(wxFileNameFromPath(m_OpenedPage));
fc7dfaf8 578
33ac7e6f 579 if (needs_refresh)
4f9297b0 580 {
fc7dfaf8
VS
581 m_tmpCanDrawLocks--;
582 Refresh();
583 }
584 else
585 m_tmpCanDrawLocks--;
586
5526e819
VS
587 return rt_val;
588}
589
590
7cb9cf89
VS
591bool wxHtmlWindow::LoadFile(const wxFileName& filename)
592{
593 wxString url = wxFileSystem::FileNameToURL(filename);
594 return LoadPage(url);
595}
596
5526e819
VS
597
598bool wxHtmlWindow::ScrollToAnchor(const wxString& anchor)
599{
4f9297b0 600 const wxHtmlCell *c = m_Cell->Find(wxHTML_COND_ISANCHOR, &anchor);
f3c82859
VS
601 if (!c)
602 {
f6bcfd97 603 wxLogWarning(_("HTML anchor %s does not exist."), anchor.c_str());
d1da8872 604 return false;
f3c82859 605 }
33ac7e6f 606 else
4f9297b0 607 {
5526e819 608 int y;
269e8200 609
4f9297b0 610 for (y = 0; c != NULL; c = c->GetParent()) y += c->GetPosY();
efba2b89 611 Scroll(-1, y / wxHTML_SCROLL_STEP);
5526e819 612 m_OpenedAnchor = anchor;
d1da8872 613 return true;
5526e819
VS
614 }
615}
616
617
d5db80c2 618void wxHtmlWindow::OnSetTitle(const wxString& title)
5526e819 619{
33ac7e6f 620 if (m_RelatedFrame)
4f9297b0 621 {
5526e819
VS
622 wxString tit;
623 tit.Printf(m_TitleFormat, title.c_str());
4f9297b0 624 m_RelatedFrame->SetTitle(tit);
5526e819 625 }
d5db80c2 626 m_OpenedPageTitle = title;
5526e819
VS
627}
628
629
630
631
632
633void wxHtmlWindow::CreateLayout()
634{
635 int ClientWidth, ClientHeight;
636
637 if (!m_Cell) return;
a547ebff 638
cc87fbed 639 if ( HasFlag(wxHW_SCROLLBAR_NEVER) )
4f9297b0 640 {
689f42f4 641 SetScrollbars(1, 1, 0, 0); // always off
a547ebff 642 GetClientSize(&ClientWidth, &ClientHeight);
4f9297b0 643 m_Cell->Layout(ClientWidth);
a547ebff 644 }
cc87fbed
VZ
645 else // !wxHW_SCROLLBAR_NEVER
646 {
a547ebff 647 GetClientSize(&ClientWidth, &ClientHeight);
4f9297b0 648 m_Cell->Layout(ClientWidth);
33ac7e6f 649 if (ClientHeight < m_Cell->GetHeight() + GetCharHeight())
e421922f 650 {
f3bcfd9b
VS
651 SetScrollbars(
652 wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
4f9297b0
VS
653 m_Cell->GetWidth() / wxHTML_SCROLL_STEP,
654 (m_Cell->GetHeight() + GetCharHeight()) / wxHTML_SCROLL_STEP
f3bcfd9b 655 /*cheat: top-level frag is always container*/);
a547ebff 656 }
4f9297b0 657 else /* we fit into window, no need for scrollbars */
e421922f 658 {
4f9297b0 659 SetScrollbars(wxHTML_SCROLL_STEP, 1, m_Cell->GetWidth() / wxHTML_SCROLL_STEP, 0); // disable...
89de9af3 660 GetClientSize(&ClientWidth, &ClientHeight);
4f9297b0 661 m_Cell->Layout(ClientWidth); // ...and relayout
89de9af3 662 }
a547ebff 663 }
5526e819
VS
664}
665
269e8200 666
5526e819
VS
667
668void wxHtmlWindow::ReadCustomization(wxConfigBase *cfg, wxString path)
669{
670 wxString oldpath;
671 wxString tmp;
d5db80c2
VS
672 int p_fontsizes[7];
673 wxString p_fff, p_ffn;
5526e819 674
33ac7e6f 675 if (path != wxEmptyString)
4f9297b0
VS
676 {
677 oldpath = cfg->GetPath();
678 cfg->SetPath(path);
5526e819
VS
679 }
680
892aeafc
VS
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);
bfb9ee96 684 for (int i = 0; i < 7; i++)
4f9297b0 685 {
66a77a74 686 tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
4f9297b0 687 p_fontsizes[i] = cfg->Read(tmp, m_Parser->m_FontsSizes[i]);
5526e819 688 }
8eb2940f 689 SetFonts(p_ffn, p_fff, p_fontsizes);
5526e819
VS
690
691 if (path != wxEmptyString)
4f9297b0 692 cfg->SetPath(oldpath);
5526e819
VS
693}
694
695
696
697void wxHtmlWindow::WriteCustomization(wxConfigBase *cfg, wxString path)
698{
699 wxString oldpath;
700 wxString tmp;
701
33ac7e6f 702 if (path != wxEmptyString)
4f9297b0
VS
703 {
704 oldpath = cfg->GetPath();
705 cfg->SetPath(path);
5526e819
VS
706 }
707
892aeafc
VS
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);
bfb9ee96 711 for (int i = 0; i < 7; i++)
4f9297b0 712 {
66a77a74 713 tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
4f9297b0 714 cfg->Write(tmp, (long) m_Parser->m_FontsSizes[i]);
5526e819
VS
715 }
716
717 if (path != wxEmptyString)
4f9297b0 718 cfg->SetPath(oldpath);
5526e819
VS
719}
720
721
722
723bool wxHtmlWindow::HistoryBack()
724{
725 wxString a, l;
726
d1da8872 727 if (m_HistoryPos < 1) return false;
5526e819 728
bbda1088
VS
729 // store scroll position into history item:
730 int x, y;
e421922f 731 GetViewStart(&x, &y);
892aeafc 732 (*m_History)[m_HistoryPos].SetPos(y);
bbda1088
VS
733
734 // go to previous position:
5526e819
VS
735 m_HistoryPos--;
736
892aeafc
VS
737 l = (*m_History)[m_HistoryPos].GetPage();
738 a = (*m_History)[m_HistoryPos].GetAnchor();
d1da8872 739 m_HistoryOn = false;
89de9af3 740 m_tmpCanDrawLocks++;
5526e819 741 if (a == wxEmptyString) LoadPage(l);
fc7dfaf8 742 else LoadPage(l + wxT("#") + a);
d1da8872 743 m_HistoryOn = true;
89de9af3 744 m_tmpCanDrawLocks--;
892aeafc 745 Scroll(0, (*m_History)[m_HistoryPos].GetPos());
5526e819 746 Refresh();
d1da8872 747 return true;
5526e819
VS
748}
749
1b113a81
VS
750bool wxHtmlWindow::HistoryCanBack()
751{
d1da8872
WS
752 if (m_HistoryPos < 1) return false;
753 return true ;
1b113a81 754}
5526e819
VS
755
756
757bool wxHtmlWindow::HistoryForward()
758{
759 wxString a, l;
760
d1da8872
WS
761 if (m_HistoryPos == -1) return false;
762 if (m_HistoryPos >= (int)m_History->GetCount() - 1)return false;
5526e819
VS
763
764 m_OpenedPage = wxEmptyString; // this will disable adding new entry into history in LoadPage()
765
766 m_HistoryPos++;
892aeafc
VS
767 l = (*m_History)[m_HistoryPos].GetPage();
768 a = (*m_History)[m_HistoryPos].GetAnchor();
d1da8872 769 m_HistoryOn = false;
89de9af3 770 m_tmpCanDrawLocks++;
5526e819 771 if (a == wxEmptyString) LoadPage(l);
fc7dfaf8 772 else LoadPage(l + wxT("#") + a);
d1da8872 773 m_HistoryOn = true;
89de9af3 774 m_tmpCanDrawLocks--;
892aeafc 775 Scroll(0, (*m_History)[m_HistoryPos].GetPos());
5526e819 776 Refresh();
d1da8872 777 return true;
5526e819
VS
778}
779
1b113a81
VS
780bool wxHtmlWindow::HistoryCanForward()
781{
d1da8872
WS
782 if (m_HistoryPos == -1) return false;
783 if (m_HistoryPos >= (int)m_History->GetCount() - 1)return false;
784 return true ;
1b113a81 785}
5526e819
VS
786
787
788void wxHtmlWindow::HistoryClear()
789{
892aeafc 790 m_History->Empty();
5526e819
VS
791 m_HistoryPos = -1;
792}
793
892aeafc
VS
794void wxHtmlWindow::AddProcessor(wxHtmlProcessor *processor)
795{
796 if (!m_Processors)
797 {
798 m_Processors = new wxHtmlProcessorList;
892aeafc 799 }
222ed1d6 800 wxHtmlProcessorList::compatibility_iterator node;
bfb9ee96 801
892aeafc
VS
802 for (node = m_Processors->GetFirst(); node; node = node->GetNext())
803 {
bfb9ee96 804 if (processor->GetPriority() > node->GetData()->GetPriority())
892aeafc
VS
805 {
806 m_Processors->Insert(node, processor);
960ba969 807 return;
892aeafc
VS
808 }
809 }
960ba969 810 m_Processors->Append(processor);
892aeafc
VS
811}
812
960ba969 813/*static */ void wxHtmlWindow::AddGlobalProcessor(wxHtmlProcessor *processor)
892aeafc 814{
960ba969 815 if (!m_GlobalProcessors)
892aeafc 816 {
960ba969 817 m_GlobalProcessors = new wxHtmlProcessorList;
892aeafc 818 }
222ed1d6 819 wxHtmlProcessorList::compatibility_iterator node;
e421922f 820
960ba969 821 for (node = m_GlobalProcessors->GetFirst(); node; node = node->GetNext())
892aeafc 822 {
bfb9ee96 823 if (processor->GetPriority() > node->GetData()->GetPriority())
892aeafc 824 {
960ba969
VS
825 m_GlobalProcessors->Insert(node, processor);
826 return;
892aeafc
VS
827 }
828 }
960ba969 829 m_GlobalProcessors->Append(processor);
892aeafc
VS
830}
831
5526e819
VS
832
833
5526e819
VS
834void wxHtmlWindow::AddFilter(wxHtmlFilter *filter)
835{
5526e819
VS
836 m_Filters.Append(filter);
837}
838
839
36c4ff4d
VS
840bool wxHtmlWindow::IsSelectionEnabled() const
841{
842#if wxUSE_CLIPBOARD
cc87fbed 843 return !HasFlag(wxHW_NO_SELECTION);
36c4ff4d
VS
844#else
845 return false;
846#endif
847}
d659d703 848
e3774124 849
1338c59a 850#if wxUSE_CLIPBOARD
977b867e 851wxString wxHtmlWindow::DoSelectionToText(wxHtmlSelection *sel)
e3774124 852{
977b867e 853 if ( !sel )
e3774124
VS
854 return wxEmptyString;
855
f30e67db
VS
856 wxClientDC dc(this);
857
977b867e 858 const wxHtmlCell *end = sel->GetToCell();
e3774124 859 wxString text;
977b867e 860 wxHtmlTerminalCellsInterator i(sel->GetFromCell(), end);
e3774124
VS
861 if ( i )
862 {
977b867e 863 text << i->ConvertToText(sel);
e3774124
VS
864 ++i;
865 }
866 const wxHtmlCell *prev = *i;
867 while ( i )
868 {
869 if ( prev->GetParent() != i->GetParent() )
870 text << _T('\n');
977b867e 871 text << i->ConvertToText(*i == end ? sel : NULL);
e3774124
VS
872 prev = *i;
873 ++i;
874 }
875 return text;
876}
877
977b867e
VS
878wxString 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
d659d703
VZ
890#endif // wxUSE_CLIPBOARD
891
8feaa81f 892bool wxHtmlWindow::CopySelection(ClipboardType t)
e3774124 893{
d659d703 894#if wxUSE_CLIPBOARD
e3774124
VS
895 if ( m_selection )
896 {
28b2ac5b 897#if defined(__UNIX__) && !defined(__WXMAC__)
e3774124 898 wxTheClipboard->UsePrimarySelection(t == Primary);
d659d703
VZ
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 )
8feaa81f 905 return false;
d659d703
VZ
906#endif // __UNIX__/!__UNIX__
907
e3774124
VS
908 if ( wxTheClipboard->Open() )
909 {
d659d703 910 const wxString txt(SelectionToText());
e3774124
VS
911 wxTheClipboard->SetData(new wxTextDataObject(txt));
912 wxTheClipboard->Close();
913 wxLogTrace(_T("wxhtmlselection"),
914 _("Copied to clipboard:\"%s\""), txt.c_str());
8feaa81f
VZ
915
916 return true;
e3774124
VS
917 }
918 }
caf448e3
WS
919#else
920 wxUnusedVar(t);
d659d703 921#endif // wxUSE_CLIPBOARD
8feaa81f
VZ
922
923 return false;
e3774124 924}
5526e819
VS
925
926
0b2dadd3 927void wxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link)
5526e819 928{
31d8b4ad
VS
929 const wxMouseEvent *e = link.GetEvent();
930 if (e == NULL || e->LeftUp())
931 LoadPage(link.GetHref());
5526e819
VS
932}
933
12148be2 934void wxHtmlWindow::OnEraseBackground(wxEraseEvent& event)
1338c59a 935{
97e490f8
VZ
936 if ( !m_bmpBg.Ok() )
937 {
518ba663
VZ
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;
97e490f8
VZ
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 }
1338c59a
VS
967}
968
969void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
5526e819 970{
1338c59a
VS
971 wxPaintDC dc(this);
972
518ba663
VZ
973 if (m_tmpCanDrawLocks > 0 || m_Cell == NULL)
974 return;
5526e819 975
b835e9bf 976 int x, y;
e421922f 977 GetViewStart(&x, &y);
1338c59a
VS
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);
d659d703 984 dcm.SelectObject(*m_backBuffer);
a03ae172 985
518ba663
VZ
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 }
a03ae172 1003
7f461f8a 1004 PrepareDC(dcm);
1338c59a
VS
1005 dcm.SetMapMode(wxMM_TEXT);
1006 dcm.SetBackgroundMode(wxTRANSPARENT);
d659d703 1007
f30e67db
VS
1008 wxHtmlRenderingInfo rinfo;
1009 wxDefaultHtmlRenderingStyle rstyle;
1010 rinfo.SetSelection(m_selection);
1011 rinfo.SetStyle(&rstyle);
1338c59a 1012 m_Cell->Draw(dcm, 0, 0,
790dbce3 1013 y * wxHTML_SCROLL_STEP + rect.GetTop(),
36c4ff4d 1014 y * wxHTML_SCROLL_STEP + rect.GetBottom(),
f30e67db 1015 rinfo);
d1da8872
WS
1016
1017//#define DEBUG_HTML_SELECTION
03693319
VS
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);
d1da8872 1025 wxHtmlCell *before =
03693319 1026 m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_BEFORE);
d1da8872 1027 wxHtmlCell *after =
03693319 1028 m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_AFTER);
d1da8872 1029
03693319
VS
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
d1da8872 1045
1338c59a
VS
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());
5526e819
VS
1051}
1052
1053
1054
1055
1056void wxHtmlWindow::OnSize(wxSizeEvent& event)
1057{
1338c59a
VS
1058 wxDELETE(m_backBuffer);
1059
5526e819
VS
1060 wxScrolledWindow::OnSize(event);
1061 CreateLayout();
1338c59a
VS
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 }
d659d703 1070
f6bcfd97 1071 Refresh();
5526e819
VS
1072}
1073
1074
fc7a2a60 1075void wxHtmlWindow::OnMouseMove(wxMouseEvent& WXUNUSED(event))
5526e819 1076{
bc55e31b 1077 wxHtmlWindowMouseHelper::HandleMouseMoved();
31d8b4ad 1078}
5526e819 1079
adf2eb2d 1080void wxHtmlWindow::OnMouseDown(wxMouseEvent& event)
31d8b4ad 1081{
0994d968 1082#if wxUSE_CLIPBOARD
adf2eb2d 1083 if ( event.LeftDown() && IsSelectionEnabled() )
4f9297b0 1084 {
0994d968
VS
1085 const long TRIPLECLICK_LEN = 200; // 0.2 sec after doubleclick
1086 if ( wxGetLocalTimeMillis() - m_lastDoubleClick <= TRIPLECLICK_LEN )
adf2eb2d 1087 {
0994d968 1088 SelectLine(CalcUnscrolledPosition(event.GetPosition()));
d659d703 1089
5de65c69 1090 (void) CopySelection();
adf2eb2d 1091 }
0994d968 1092 else
d659d703 1093 {
0994d968 1094 m_makingSelection = true;
d659d703 1095
0994d968
VS
1096 if ( m_selection )
1097 {
1098 wxDELETE(m_selection);
1099 Refresh();
1100 }
1101 m_tmpSelFromPos = CalcUnscrolledPosition(event.GetPosition());
1102 m_tmpSelFromCell = NULL;
5526e819 1103
0994d968
VS
1104 CaptureMouse();
1105 }
adf2eb2d 1106 }
caf448e3
WS
1107#else
1108 wxUnusedVar(event);
d659d703 1109#endif // wxUSE_CLIPBOARD
adf2eb2d 1110}
5526e819 1111
adf2eb2d
VS
1112void wxHtmlWindow::OnMouseUp(wxMouseEvent& event)
1113{
1338c59a 1114#if wxUSE_CLIPBOARD
adf2eb2d
VS
1115 if ( m_makingSelection )
1116 {
1117 ReleaseMouse();
1118 m_makingSelection = false;
1119
1120 // did the user move the mouse far enough from starting point?
8feaa81f 1121 if ( CopySelection(Primary) )
adf2eb2d
VS
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 }
d659d703
VZ
1128#endif // wxUSE_CLIPBOARD
1129
adf2eb2d 1130 SetFocus();
f6010d8f 1131
bc55e31b
VS
1132 wxPoint pos = CalcUnscrolledPosition(event.GetPosition());
1133 wxHtmlWindowMouseHelper::HandleMouseClick(m_Cell, pos, event);
5526e819
VS
1134}
1135
63e819f2
VS
1136#if wxUSE_CLIPBOARD
1137void 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
5526e819
VS
1149
1150
5180055b
JS
1151void wxHtmlWindow::OnInternalIdle()
1152{
1153 wxWindow::OnInternalIdle();
d1da8872 1154
bc55e31b 1155 if (m_Cell != NULL && DidMouseMove())
4f9297b0 1156 {
03693319
VS
1157#ifdef DEBUG_HTML_SELECTION
1158 Refresh();
1159#endif
adf2eb2d
VS
1160 int xc, yc, x, y;
1161 wxGetMousePosition(&xc, &yc);
1162 ScreenToClient(&xc, &yc);
1163 CalcUnscrolledPosition(xc, yc, &x, &y);
0cb9cfb2 1164
f6010d8f 1165 wxHtmlCell *cell = m_Cell->FindCellByPos(x, y);
adf2eb2d
VS
1166
1167 // handle selection update:
1168 if ( m_makingSelection )
1169 {
adf2eb2d 1170 if ( !m_tmpSelFromCell )
748418c0
VS
1171 m_tmpSelFromCell = m_Cell->FindCellByPos(
1172 m_tmpSelFromPos.x,m_tmpSelFromPos.y);
d1da8872 1173
03693319
VS
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 }
d1da8872 1195 bool goingDown = dirFromPos.y < y ||
03693319
VS
1196 (dirFromPos.y == y && dirFromPos.x < x);
1197
1198 // determine selection span:
748418c0 1199 if ( /*still*/ !m_tmpSelFromCell )
adf2eb2d
VS
1200 {
1201 if (goingDown)
1202 {
5a1597e9
VS
1203 m_tmpSelFromCell = m_Cell->FindCellByPos(
1204 m_tmpSelFromPos.x,m_tmpSelFromPos.y,
1205 wxHTML_FIND_NEAREST_AFTER);
adf2eb2d
VS
1206 if (!m_tmpSelFromCell)
1207 m_tmpSelFromCell = m_Cell->GetFirstTerminal();
1208 }
1209 else
1210 {
5a1597e9
VS
1211 m_tmpSelFromCell = m_Cell->FindCellByPos(
1212 m_tmpSelFromPos.x,m_tmpSelFromPos.y,
1213 wxHTML_FIND_NEAREST_BEFORE);
adf2eb2d
VS
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,
03693319 1225 wxHTML_FIND_NEAREST_BEFORE);
adf2eb2d
VS
1226 if (!selcell)
1227 selcell = m_Cell->GetLastTerminal();
1228 }
1229 else
1230 {
1231 selcell = m_Cell->FindCellByPos(x, y,
03693319 1232 wxHTML_FIND_NEAREST_AFTER);
adf2eb2d
VS
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
d659d703 1240 // visible cells.
adf2eb2d 1241 if ( selcell && m_tmpSelFromCell )
d659d703 1242 {
adf2eb2d
VS
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 {
e3774124 1256 if ( m_tmpSelFromCell->IsBefore(selcell) )
adf2eb2d
VS
1257 {
1258 m_selection->Set(m_tmpSelFromPos, m_tmpSelFromCell,
f30e67db 1259 wxPoint(x,y), selcell); }
adf2eb2d
VS
1260 else
1261 {
1262 m_selection->Set(wxPoint(x,y), selcell,
1263 m_tmpSelFromPos, m_tmpSelFromCell);
1264 }
1338c59a
VS
1265 m_selection->ClearPrivPos();
1266 Refresh();
adf2eb2d
VS
1267 }
1268 }
1269 }
d659d703 1270
adf2eb2d 1271 // handle cursor and status bar text changes:
f6010d8f 1272
bc55e31b
VS
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);
5526e819
VS
1280 }
1281}
1282
e3774124 1283#if wxUSE_CLIPBOARD
1338c59a
VS
1284void wxHtmlWindow::StopAutoScrolling()
1285{
1286 if ( m_timerAutoScroll )
1287 {
1288 wxDELETE(m_timerAutoScroll);
1289 }
1290}
1291
1292void wxHtmlWindow::OnMouseEnter(wxMouseEvent& event)
1293{
1294 StopAutoScrolling();
1295 event.Skip();
1296}
1297
1298void 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
e3774124
VS
1363void wxHtmlWindow::OnKeyUp(wxKeyEvent& event)
1364{
abe64011 1365 if ( IsSelectionEnabled() && event.GetKeyCode() == 'C' && event.CmdDown() )
e3774124 1366 {
5de65c69 1367 (void) CopySelection();
e3774124 1368 }
e3774124
VS
1369}
1370
fc7a2a60 1371void wxHtmlWindow::OnCopy(wxCommandEvent& WXUNUSED(event))
e3774124 1372{
5de65c69 1373 (void) CopySelection();
e3774124 1374}
d659d703 1375
31eefb99
VS
1376void wxHtmlWindow::OnDoubleClick(wxMouseEvent& event)
1377{
1378 // select word under cursor:
1379 if ( IsSelectionEnabled() )
1380 {
0994d968 1381 SelectWord(CalcUnscrolledPosition(event.GetPosition()));
d659d703 1382
5de65c69 1383 (void) CopySelection(Primary);
d659d703 1384
0994d968 1385 m_lastDoubleClick = wxGetLocalTimeMillis();
31eefb99
VS
1386 }
1387 else
1388 event.Skip();
1389}
0994d968
VS
1390
1391void wxHtmlWindow::SelectWord(const wxPoint& pos)
1392{
2a536376 1393 if ( m_Cell )
0994d968 1394 {
2a536376
VS
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 }
0994d968
VS
1404 }
1405}
1406
1407void wxHtmlWindow::SelectLine(const wxPoint& pos)
1408{
2a536376 1409 if ( m_Cell )
0994d968 1410 {
2a536376
VS
1411 wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
1412 if ( cell )
0994d968 1413 {
2a536376
VS
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;
0994d968 1437
2a536376
VS
1438 // find first cell of line:
1439 for ( c = cell->GetParent()->GetFirstChild();
1440 c && c != cell; c = c->GetNext())
0994d968 1441 {
2a536376
VS
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;
0994d968 1450 }
2a536376
VS
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();
0994d968 1459 }
2a536376
VS
1460 }
1461}
d659d703 1462
2a536376
VS
1463void wxHtmlWindow::SelectAll()
1464{
1465 if ( m_Cell )
1466 {
0994d968
VS
1467 delete m_selection;
1468 m_selection = new wxHtmlSelection();
2a536376 1469 m_selection->Set(m_Cell->GetFirstTerminal(), m_Cell->GetLastTerminal());
0994d968
VS
1470 Refresh();
1471 }
1472}
2a536376 1473
d659d703 1474#endif // wxUSE_CLIPBOARD
e3774124
VS
1475
1476
5526e819 1477
bfb9ee96 1478IMPLEMENT_ABSTRACT_CLASS(wxHtmlProcessor,wxObject)
5526e819 1479
786a2425
SC
1480#if wxUSE_EXTENDED_RTTI
1481IMPLEMENT_DYNAMIC_CLASS_XTI(wxHtmlWindow, wxScrolledWindow,"wx/html/htmlwin.h")
1482
459f2add 1483wxBEGIN_PROPERTIES_TABLE(wxHtmlWindow)
786a2425 1484/*
d1da8872
WS
1485 TODO PROPERTIES
1486 style , wxHW_SCROLLBAR_AUTO
1487 borders , (dimension)
1488 url , string
1489 htmlcode , string
786a2425 1490*/
459f2add 1491wxEND_PROPERTIES_TABLE()
786a2425 1492
459f2add
SC
1493wxBEGIN_HANDLERS_TABLE(wxHtmlWindow)
1494wxEND_HANDLERS_TABLE()
786a2425 1495
d1da8872 1496wxCONSTRUCTOR_5( wxHtmlWindow , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
786a2425 1497#else
5526e819 1498IMPLEMENT_DYNAMIC_CLASS(wxHtmlWindow,wxScrolledWindow)
786a2425 1499#endif
5526e819
VS
1500
1501BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
1502 EVT_SIZE(wxHtmlWindow::OnSize)
adf2eb2d
VS
1503 EVT_LEFT_DOWN(wxHtmlWindow::OnMouseDown)
1504 EVT_LEFT_UP(wxHtmlWindow::OnMouseUp)
1505 EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp)
31d8b4ad 1506 EVT_MOTION(wxHtmlWindow::OnMouseMove)
1338c59a
VS
1507 EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground)
1508 EVT_PAINT(wxHtmlWindow::OnPaint)
e3774124 1509#if wxUSE_CLIPBOARD
31eefb99 1510 EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick)
1338c59a
VS
1511 EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter)
1512 EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave)
63e819f2 1513 EVT_MOUSE_CAPTURE_LOST(wxHtmlWindow::OnMouseCaptureLost)
e3774124
VS
1514 EVT_KEY_UP(wxHtmlWindow::OnKeyUp)
1515 EVT_MENU(wxID_COPY, wxHtmlWindow::OnCopy)
d659d703 1516#endif // wxUSE_CLIPBOARD
5526e819
VS
1517END_EVENT_TABLE()
1518
bc55e31b
VS
1519//-----------------------------------------------------------------------------
1520// wxHtmlWindowInterface implementation in wxHtmlWindow
1521//-----------------------------------------------------------------------------
1522
1523void wxHtmlWindow::SetHTMLWindowTitle(const wxString& title)
1524{
1525 OnSetTitle(title);
1526}
1527
1528void wxHtmlWindow::OnHTMLLinkClicked(const wxHtmlLinkInfo& link)
1529{
1530 OnLinkClicked(link);
1531}
1532
1533wxHtmlOpeningStatus wxHtmlWindow::OnHTMLOpeningURL(wxHtmlURLType type,
1534 const wxString& url,
1535 wxString *redirect) const
1536{
1537 return OnOpeningURL(type, url, redirect);
1538}
1539
1540wxPoint wxHtmlWindow::HTMLCoordsToWindow(wxHtmlCell *WXUNUSED(cell),
1541 const wxPoint& pos) const
1542{
1543 return CalcScrolledPosition(pos);
1544}
1545
1546wxWindow* wxHtmlWindow::GetHTMLWindow()
1547{
1548 return this;
1549}
1550
1551wxColour wxHtmlWindow::GetHTMLBackgroundColour() const
1552{
1553 return GetBackgroundColour();
1554}
1555
1556void wxHtmlWindow::SetHTMLBackgroundColour(const wxColour& clr)
1557{
1558 SetBackgroundColour(clr);
1559}
1560
1561void wxHtmlWindow::SetHTMLBackgroundImage(const wxBitmap& bmpBg)
1562{
1563 SetBackgroundImage(bmpBg);
1564}
5526e819 1565
bc55e31b
VS
1566void wxHtmlWindow::SetHTMLStatusText(const wxString& text)
1567{
1568#if wxUSE_STATUSBAR
1569 if (m_RelatedStatusBar != -1)
1570 m_RelatedFrame->SetStatusText(text, m_RelatedStatusBar);
80d99525
WS
1571#else
1572 wxUnusedVar(text);
bc55e31b
VS
1573#endif // wxUSE_STATUSBAR
1574}
5526e819 1575
88a1b648
VS
1576/*static*/
1577wxCursor 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
1597wxCursor wxHtmlWindow::GetHTMLCursor(HTMLCursor type) const
1598{
1599 return GetDefaultHTMLCursor(type);
1600}
1601
5526e819 1602
bc55e31b
VS
1603//-----------------------------------------------------------------------------
1604// wxHtmlWinModule
1605//-----------------------------------------------------------------------------
5526e819 1606
a76015e6
VS
1607// A module to allow initialization/cleanup
1608// without calling these functions from app.cpp or from
1609// the user's application.
1610
1611class wxHtmlWinModule: public wxModule
1612{
1613DECLARE_DYNAMIC_CLASS(wxHtmlWinModule)
1614public:
1615 wxHtmlWinModule() : wxModule() {}
d1da8872 1616 bool OnInit() { return true; }
a76015e6
VS
1617 void OnExit() { wxHtmlWindow::CleanUpStatics(); }
1618};
1619
1620IMPLEMENT_DYNAMIC_CLASS(wxHtmlWinModule, wxModule)
1621
5526e819 1622
0cecad31
VS
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"
1626FORCE_WXHTML_MODULES()
5526e819 1627
d659d703 1628#endif // wxUSE_HTML