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