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