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