Files
wxWidgets/src/html/htmlwin.cpp
Vadim Zeitlin 49b489e80f Fix erasing wxHtmlWindow background in wxUniv.
Prevent the default wxWindow-level wxEVT_ERASE_BACKGROUND handler from being
used in wxUniv for wxHtmlWindow. This is unnecessary as it has its own handler
anyhow and also doesn't work for some reason as erasing wxMemoryDC by drawing
a solid rectangle over it seems to be broken in at least wxX11.

Work around this problem by erasing the background in wxHtmlWindow itself if
no user-defined (as opposed to any, including one defined in wxWindow itself)
handler for this event exists.

Closes #13880.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@71300 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-04-28 22:24:43 +00:00

1822 lines
53 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/html/htmlwin.cpp
// Purpose: wxHtmlWindow class for parsing & displaying HTML (implementation)
// Author: Vaclav Slavik
// RCS-ID: $Id$
// Copyright: (c) 1999 Vaclav Slavik
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_HTML && wxUSE_STREAMS
#ifndef WX_PRECOMP
#include "wx/list.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/dcclient.h"
#include "wx/frame.h"
#include "wx/dcmemory.h"
#include "wx/timer.h"
#include "wx/settings.h"
#include "wx/dataobj.h"
#include "wx/statusbr.h"
#endif
#include "wx/html/htmlwin.h"
#include "wx/html/htmlproc.h"
#include "wx/clipbrd.h"
#include "wx/recguard.h"
#include "wx/arrimpl.cpp"
#include "wx/listimpl.cpp"
// uncomment this line to visually show the extent of the selection
//#define DEBUG_HTML_SELECTION
// HTML events:
IMPLEMENT_DYNAMIC_CLASS(wxHtmlLinkEvent, wxCommandEvent)
IMPLEMENT_DYNAMIC_CLASS(wxHtmlCellEvent, wxCommandEvent)
wxDEFINE_EVENT( wxEVT_COMMAND_HTML_CELL_CLICKED, wxHtmlCellEvent );
wxDEFINE_EVENT( wxEVT_COMMAND_HTML_CELL_HOVER, wxHtmlCellEvent );
wxDEFINE_EVENT( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEvent );
#if wxUSE_CLIPBOARD
// ----------------------------------------------------------------------------
// wxHtmlWinAutoScrollTimer: the timer used to generate a stream of scroll
// events when a captured mouse is held outside the window
// ----------------------------------------------------------------------------
class wxHtmlWinAutoScrollTimer : public wxTimer
{
public:
wxHtmlWinAutoScrollTimer(wxScrolledWindow *win,
wxEventType eventTypeToSend,
int pos, int orient)
{
m_win = win;
m_eventType = eventTypeToSend;
m_pos = pos;
m_orient = orient;
}
virtual void Notify();
private:
wxScrolledWindow *m_win;
wxEventType m_eventType;
int m_pos,
m_orient;
wxDECLARE_NO_COPY_CLASS(wxHtmlWinAutoScrollTimer);
};
void wxHtmlWinAutoScrollTimer::Notify()
{
// only do all this as long as the window is capturing the mouse
if ( wxWindow::GetCapture() != m_win )
{
Stop();
}
else // we still capture the mouse, continue generating events
{
// first scroll the window if we are allowed to do it
wxScrollWinEvent event1(m_eventType, m_pos, m_orient);
event1.SetEventObject(m_win);
if ( m_win->GetEventHandler()->ProcessEvent(event1) )
{
// and then send a pseudo mouse-move event to refresh the selection
wxMouseEvent event2(wxEVT_MOTION);
wxGetMousePosition(&event2.m_x, &event2.m_y);
// the mouse event coordinates should be client, not screen as
// returned by wxGetMousePosition
wxWindow *parentTop = m_win;
while ( parentTop->GetParent() )
parentTop = parentTop->GetParent();
wxPoint ptOrig = parentTop->GetPosition();
event2.m_x -= ptOrig.x;
event2.m_y -= ptOrig.y;
event2.SetEventObject(m_win);
// FIXME: we don't fill in the other members - ok?
m_win->GetEventHandler()->ProcessEvent(event2);
}
else // can't scroll further, stop
{
Stop();
}
}
}
#endif // wxUSE_CLIPBOARD
//-----------------------------------------------------------------------------
// wxHtmlHistoryItem
//-----------------------------------------------------------------------------
// item of history list
class WXDLLIMPEXP_HTML wxHtmlHistoryItem
{
public:
wxHtmlHistoryItem(const wxString& p, const wxString& a) {m_Page = p, m_Anchor = a, m_Pos = 0;}
int GetPos() const {return m_Pos;}
void SetPos(int p) {m_Pos = p;}
const wxString& GetPage() const {return m_Page;}
const wxString& GetAnchor() const {return m_Anchor;}
private:
wxString m_Page;
wxString m_Anchor;
int m_Pos;
};
//-----------------------------------------------------------------------------
// our private arrays:
//-----------------------------------------------------------------------------
WX_DECLARE_OBJARRAY(wxHtmlHistoryItem, wxHtmlHistoryArray);
WX_DEFINE_OBJARRAY(wxHtmlHistoryArray)
WX_DECLARE_LIST(wxHtmlProcessor, wxHtmlProcessorList);
WX_DEFINE_LIST(wxHtmlProcessorList)
//-----------------------------------------------------------------------------
// wxHtmlWindowMouseHelper
//-----------------------------------------------------------------------------
wxHtmlWindowMouseHelper::wxHtmlWindowMouseHelper(wxHtmlWindowInterface *iface)
: m_tmpMouseMoved(false),
m_tmpLastLink(NULL),
m_tmpLastCell(NULL),
m_interface(iface)
{
}
void wxHtmlWindowMouseHelper::HandleMouseMoved()
{
m_tmpMouseMoved = true;
}
bool wxHtmlWindowMouseHelper::HandleMouseClick(wxHtmlCell *rootCell,
const wxPoint& pos,
const wxMouseEvent& event)
{
if (!rootCell)
return false;
wxHtmlCell *cell = rootCell->FindCellByPos(pos.x, pos.y);
// this check is needed because FindCellByPos returns terminal cell and
// containers may have empty borders -- in this case NULL will be
// returned
if (!cell)
return false;
// adjust the coordinates to be relative to this cell:
wxPoint relpos = pos - cell->GetAbsPos(rootCell);
return OnCellClicked(cell, relpos.x, relpos.y, event);
}
void wxHtmlWindowMouseHelper::HandleIdle(wxHtmlCell *rootCell,
const wxPoint& pos)
{
wxHtmlCell *cell = rootCell ? rootCell->FindCellByPos(pos.x, pos.y) : NULL;
if (cell != m_tmpLastCell)
{
wxHtmlLinkInfo *lnk = NULL;
if (cell)
{
// adjust the coordinates to be relative to this cell:
wxPoint relpos = pos - cell->GetAbsPos(rootCell);
lnk = cell->GetLink(relpos.x, relpos.y);
}
wxCursor cur;
if (cell)
cur = cell->GetMouseCursor(m_interface);
else
cur = m_interface->GetHTMLCursor(
wxHtmlWindowInterface::HTMLCursor_Default);
m_interface->GetHTMLWindow()->SetCursor(cur);
if (lnk != m_tmpLastLink)
{
if (lnk)
m_interface->SetHTMLStatusText(lnk->GetHref());
else
m_interface->SetHTMLStatusText(wxEmptyString);
m_tmpLastLink = lnk;
}
m_tmpLastCell = cell;
}
else // mouse moved but stayed in the same cell
{
if ( cell )
{
OnCellMouseHover(cell, pos.x, pos.y);
}
}
m_tmpMouseMoved = false;
}
bool wxHtmlWindowMouseHelper::OnCellClicked(wxHtmlCell *cell,
wxCoord x, wxCoord y,
const wxMouseEvent& event)
{
wxHtmlCellEvent ev(wxEVT_COMMAND_HTML_CELL_CLICKED,
m_interface->GetHTMLWindow()->GetId(),
cell, wxPoint(x,y), event);
if (!m_interface->GetHTMLWindow()->GetEventHandler()->ProcessEvent(ev))
{
// if the event wasn't handled, do the default processing here:
wxASSERT_MSG( cell, wxT("can't be called with NULL cell") );
cell->ProcessMouseClick(m_interface, ev.GetPoint(), ev.GetMouseEvent());
}
// true if a link was clicked, false otherwise
return ev.GetLinkClicked();
}
void wxHtmlWindowMouseHelper::OnCellMouseHover(wxHtmlCell * cell,
wxCoord x,
wxCoord y)
{
wxHtmlCellEvent ev(wxEVT_COMMAND_HTML_CELL_HOVER,
m_interface->GetHTMLWindow()->GetId(),
cell, wxPoint(x,y), wxMouseEvent());
m_interface->GetHTMLWindow()->GetEventHandler()->ProcessEvent(ev);
}
//-----------------------------------------------------------------------------
// wxHtmlWindow
//-----------------------------------------------------------------------------
wxList wxHtmlWindow::m_Filters;
wxHtmlFilter *wxHtmlWindow::m_DefaultFilter = NULL;
wxHtmlProcessorList *wxHtmlWindow::m_GlobalProcessors = NULL;
wxCursor *wxHtmlWindow::ms_cursorLink = NULL;
wxCursor *wxHtmlWindow::ms_cursorText = NULL;
void wxHtmlWindow::CleanUpStatics()
{
wxDELETE(m_DefaultFilter);
WX_CLEAR_LIST(wxList, m_Filters);
if (m_GlobalProcessors)
WX_CLEAR_LIST(wxHtmlProcessorList, *m_GlobalProcessors);
wxDELETE(m_GlobalProcessors);
wxDELETE(ms_cursorLink);
wxDELETE(ms_cursorText);
}
void wxHtmlWindow::Init()
{
m_tmpCanDrawLocks = 0;
m_FS = new wxFileSystem();
#if wxUSE_STATUSBAR
m_RelatedStatusBar = NULL;
m_RelatedStatusBarIndex = -1;
#endif // wxUSE_STATUSBAR
m_RelatedFrame = NULL;
m_TitleFormat = wxT("%s");
m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
m_Cell = NULL;
m_Parser = new wxHtmlWinParser(this);
m_Parser->SetFS(m_FS);
m_HistoryPos = -1;
m_HistoryOn = true;
m_History = new wxHtmlHistoryArray;
m_Processors = NULL;
SetBorders(10);
m_selection = NULL;
m_makingSelection = false;
#if wxUSE_CLIPBOARD
m_timerAutoScroll = NULL;
m_lastDoubleClick = 0;
#endif // wxUSE_CLIPBOARD
m_tmpSelFromCell = NULL;
}
bool wxHtmlWindow::Create(wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size,
long style, const wxString& name)
{
if (!wxScrolledWindow::Create(parent, id, pos, size,
style | wxVSCROLL | wxHSCROLL,
name))
return false;
// We can't erase our background in EVT_ERASE_BACKGROUND handler and use
// double buffering in EVT_PAINT handler as this requires blitting back
// something already drawn on the window to the backing store bitmap when
// handling EVT_PAINT but blitting in this direction is simply not
// supported by OS X.
//
// So instead we use a hack with artificial EVT_ERASE_BACKGROUND generation
// from OnPaint() and this means that we never need the "real" erase event
// at all so disable it to avoid executing any user-defined handlers twice
// (and to avoid processing unnecessary event if no handlers are defined).
SetBackgroundStyle(wxBG_STYLE_PAINT);
SetPage(wxT("<html><body></body></html>"));
SetInitialSize(size);
return true;
}
wxHtmlWindow::~wxHtmlWindow()
{
#if wxUSE_CLIPBOARD
StopAutoScrolling();
#endif // wxUSE_CLIPBOARD
HistoryClear();
delete m_selection;
delete m_Cell;
if ( m_Processors )
{
WX_CLEAR_LIST(wxHtmlProcessorList, *m_Processors);
}
delete m_Parser;
delete m_FS;
delete m_History;
delete m_Processors;
}
void wxHtmlWindow::SetRelatedFrame(wxFrame* frame, const wxString& format)
{
m_RelatedFrame = frame;
m_TitleFormat = format;
}
#if wxUSE_STATUSBAR
void wxHtmlWindow::SetRelatedStatusBar(int index)
{
m_RelatedStatusBarIndex = index;
}
void wxHtmlWindow::SetRelatedStatusBar(wxStatusBar* statusbar, int index)
{
m_RelatedStatusBar = statusbar;
m_RelatedStatusBarIndex = index;
}
#endif // wxUSE_STATUSBAR
void wxHtmlWindow::SetFonts(const wxString& normal_face, const wxString& fixed_face, const int *sizes)
{
m_Parser->SetFonts(normal_face, fixed_face, sizes);
// re-layout the page after changing fonts:
DoSetPage(*(m_Parser->GetSource()));
}
void wxHtmlWindow::SetStandardFonts(int size,
const wxString& normal_face,
const wxString& fixed_face)
{
m_Parser->SetStandardFonts(size, normal_face, fixed_face);
// re-layout the page after changing fonts:
DoSetPage(*(m_Parser->GetSource()));
}
bool wxHtmlWindow::SetPage(const wxString& source)
{
m_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
return DoSetPage(source);
}
bool wxHtmlWindow::DoSetPage(const wxString& source)
{
wxString newsrc(source);
wxDELETE(m_selection);
// we will soon delete all the cells, so clear pointers to them:
m_tmpSelFromCell = NULL;
// pass HTML through registered processors:
if (m_Processors || m_GlobalProcessors)
{
wxHtmlProcessorList::compatibility_iterator nodeL, nodeG;
int prL, prG;
if ( m_Processors )
nodeL = m_Processors->GetFirst();
if ( m_GlobalProcessors )
nodeG = m_GlobalProcessors->GetFirst();
// VS: there are two lists, global and local, both of them sorted by
// priority. Since we have to go through _both_ lists with
// decreasing priority, we "merge-sort" the lists on-line by
// processing that one of the two heads that has higher priority
// in every iteration
while (nodeL || nodeG)
{
prL = (nodeL) ? nodeL->GetData()->GetPriority() : -1;
prG = (nodeG) ? nodeG->GetData()->GetPriority() : -1;
if (prL > prG)
{
if (nodeL->GetData()->IsEnabled())
newsrc = nodeL->GetData()->Process(newsrc);
nodeL = nodeL->GetNext();
}
else // prL <= prG
{
if (nodeG->GetData()->IsEnabled())
newsrc = nodeG->GetData()->Process(newsrc);
nodeG = nodeG->GetNext();
}
}
}
// ...and run the parser on it:
wxClientDC *dc = new wxClientDC(this);
dc->SetMapMode(wxMM_TEXT);
SetBackgroundColour(wxColour(0xFF, 0xFF, 0xFF));
SetBackgroundImage(wxNullBitmap);
m_Parser->SetDC(dc);
// notice that it's important to set m_Cell to NULL here before calling
// Parse() below, even if it will be overwritten by its return value as
// without this we may crash if it's used from inside Parse(), so use
// wxDELETE() and not just delete here
wxDELETE(m_Cell);
m_Cell = (wxHtmlContainerCell*) m_Parser->Parse(newsrc);
delete dc;
m_Cell->SetIndent(m_Borders, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
m_Cell->SetAlignHor(wxHTML_ALIGN_CENTER);
CreateLayout();
if (m_tmpCanDrawLocks == 0)
Refresh();
return true;
}
bool wxHtmlWindow::AppendToPage(const wxString& source)
{
return DoSetPage(*(GetParser()->GetSource()) + source);
}
bool wxHtmlWindow::LoadPage(const wxString& location)
{
wxCHECK_MSG( !location.empty(), false, "location must be non-empty" );
wxBusyCursor busyCursor;
bool rt_val;
bool needs_refresh = false;
m_tmpCanDrawLocks++;
if (m_HistoryOn && (m_HistoryPos != -1))
{
// store scroll position into history item:
int x, y;
GetViewStart(&x, &y);
(*m_History)[m_HistoryPos].SetPos(y);
}
// first check if we're moving to an anchor in the same page
size_t posLocalAnchor = location.Find('#');
if ( posLocalAnchor != wxString::npos && posLocalAnchor != 0 )
{
// check if the part before the anchor is the same as the (either
// relative or absolute) URI of the current page
const wxString beforeAnchor = location.substr(0, posLocalAnchor);
if ( beforeAnchor != m_OpenedPage &&
m_FS->GetPath() + beforeAnchor != m_OpenedPage )
{
// indicate that we're not moving to a local anchor
posLocalAnchor = wxString::npos;
}
}
if ( posLocalAnchor != wxString::npos )
{
m_tmpCanDrawLocks--;
rt_val = ScrollToAnchor(location.substr(posLocalAnchor + 1));
m_tmpCanDrawLocks++;
}
else // moving to another page
{
needs_refresh = true;
#if wxUSE_STATUSBAR
// load&display it:
if (m_RelatedStatusBarIndex != -1)
{
SetHTMLStatusText(_("Connecting..."));
Refresh(false);
}
#endif // wxUSE_STATUSBAR
wxFSFile *f = m_Parser->OpenURL(wxHTML_URL_PAGE, location);
// try to interpret 'location' as filename instead of URL:
if (f == NULL)
{
wxFileName fn(location);
wxString location2 = wxFileSystem::FileNameToURL(fn);
f = m_Parser->OpenURL(wxHTML_URL_PAGE, location2);
}
if (f == NULL)
{
wxLogError(_("Unable to open requested HTML document: %s"), location.c_str());
m_tmpCanDrawLocks--;
SetHTMLStatusText(wxEmptyString);
return false;
}
else
{
wxList::compatibility_iterator node;
wxString src = wxEmptyString;
#if wxUSE_STATUSBAR
if (m_RelatedStatusBarIndex != -1)
{
wxString msg = _("Loading : ") + location;
SetHTMLStatusText(msg);
Refresh(false);
}
#endif // wxUSE_STATUSBAR
node = m_Filters.GetFirst();
while (node)
{
wxHtmlFilter *h = (wxHtmlFilter*) node->GetData();
if (h->CanRead(*f))
{
src = h->ReadFile(*f);
break;
}
node = node->GetNext();
}
if (src == wxEmptyString)
{
if (m_DefaultFilter == NULL) m_DefaultFilter = GetDefaultFilter();
src = m_DefaultFilter->ReadFile(*f);
}
m_FS->ChangePathTo(f->GetLocation());
rt_val = SetPage(src);
m_OpenedPage = f->GetLocation();
if (f->GetAnchor() != wxEmptyString)
{
ScrollToAnchor(f->GetAnchor());
}
delete f;
#if wxUSE_STATUSBAR
if (m_RelatedStatusBarIndex != -1)
{
SetHTMLStatusText(_("Done"));
}
#endif // wxUSE_STATUSBAR
}
}
if (m_HistoryOn) // add this page to history there:
{
int c = m_History->GetCount() - (m_HistoryPos + 1);
if (m_HistoryPos < 0 ||
(*m_History)[m_HistoryPos].GetPage() != m_OpenedPage ||
(*m_History)[m_HistoryPos].GetAnchor() != m_OpenedAnchor)
{
m_HistoryPos++;
for (int i = 0; i < c; i++)
m_History->RemoveAt(m_HistoryPos);
m_History->Add(new wxHtmlHistoryItem(m_OpenedPage, m_OpenedAnchor));
}
}
if (m_OpenedPageTitle == wxEmptyString)
OnSetTitle(wxFileNameFromPath(m_OpenedPage));
if (needs_refresh)
{
m_tmpCanDrawLocks--;
Refresh();
}
else
m_tmpCanDrawLocks--;
return rt_val;
}
bool wxHtmlWindow::LoadFile(const wxFileName& filename)
{
wxString url = wxFileSystem::FileNameToURL(filename);
return LoadPage(url);
}
bool wxHtmlWindow::ScrollToAnchor(const wxString& anchor)
{
const wxHtmlCell *c = m_Cell->Find(wxHTML_COND_ISANCHOR, &anchor);
if (!c)
{
wxLogWarning(_("HTML anchor %s does not exist."), anchor.c_str());
return false;
}
else
{
// Go to next visible cell in current container, if it exists. This
// yields a bit better (even though still imperfect) results in that
// there's better chance of using a suitable cell for upper Y
// coordinate value. See bug #11406 for additional discussion.
const wxHtmlCell *c_save = c;
while ( c && c->IsFormattingCell() )
c = c->GetNext();
if ( !c )
c = c_save;
int y;
for (y = 0; c != NULL; c = c->GetParent()) y += c->GetPosY();
Scroll(-1, y / wxHTML_SCROLL_STEP);
m_OpenedAnchor = anchor;
return true;
}
}
void wxHtmlWindow::OnSetTitle(const wxString& title)
{
if (m_RelatedFrame)
{
wxString tit;
tit.Printf(m_TitleFormat, title.c_str());
m_RelatedFrame->SetTitle(tit);
}
m_OpenedPageTitle = title;
}
// return scroll steps such that a) scrollbars aren't shown needlessly
// and b) entire content is viewable (i.e. round up)
static int ScrollSteps(int size, int available)
{
if ( size <= available )
return 0;
else
return (size + wxHTML_SCROLL_STEP - 1) / wxHTML_SCROLL_STEP;
}
void wxHtmlWindow::CreateLayout()
{
// SetScrollbars() results in size change events -- and thus a nested
// CreateLayout() call -- on some platforms. Ignore nested calls, toplevel
// CreateLayout() will do the right thing eventually.
static wxRecursionGuardFlag s_flagReentrancy;
wxRecursionGuard guard(s_flagReentrancy);
if ( guard.IsInside() )
return;
if (!m_Cell)
return;
int clientWidth, clientHeight;
GetClientSize(&clientWidth, &clientHeight);
const int vscrollbar = wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
const int hscrollbar = wxSystemSettings::GetMetric(wxSYS_HSCROLL_Y);
if ( HasScrollbar(wxHORIZONTAL) )
clientHeight += hscrollbar;
if ( HasScrollbar(wxVERTICAL) )
clientWidth += vscrollbar;
if ( HasFlag(wxHW_SCROLLBAR_NEVER) )
{
SetScrollbars(1, 1, 0, 0); // always off
m_Cell->Layout(clientWidth);
}
else // !wxHW_SCROLLBAR_NEVER
{
// Lay the content out with the assumption that it's too large to fit
// in the window (this is likely to be the case):
m_Cell->Layout(clientWidth - vscrollbar);
// If the layout is wider than the window, horizontal scrollbar will
// certainly be shown. Account for it here for subsequent computations.
if ( m_Cell->GetWidth() > clientWidth )
clientHeight -= hscrollbar;
if ( m_Cell->GetHeight() <= clientHeight )
{
// we fit into the window, hide vertical scrollbar:
SetScrollbars
(
wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
ScrollSteps(m_Cell->GetWidth(), clientWidth - vscrollbar),
0
);
// ...and redo the layout to use the extra space
m_Cell->Layout(clientWidth);
}
else
{
// If the content doesn't fit into the window by only a small
// margin, chances are that it may fit fully with scrollbar turned
// off. It's something worth trying but on the other hand, we don't
// want to waste too much time redoing the layout (twice!) for
// long -- and thus expensive to layout -- pages. The cut-off value
// is an arbitrary heuristics.
static const int SMALL_OVERLAP = 60;
if ( m_Cell->GetHeight() <= clientHeight + SMALL_OVERLAP )
{
m_Cell->Layout(clientWidth);
if ( m_Cell->GetHeight() <= clientHeight )
{
// Great, we fit in. Hide the scrollbar.
SetScrollbars
(
wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
ScrollSteps(m_Cell->GetWidth(), clientWidth),
0
);
return;
}
else
{
// That didn't work out, go back to previous layout. Note
// that redoing the layout once again here isn't as bad as
// it looks -- thanks to the small cut-off value, it's a
// reasonably small page.
m_Cell->Layout(clientWidth - vscrollbar);
}
}
// else: the page is very long, it will certainly need scrollbar
SetScrollbars
(
wxHTML_SCROLL_STEP, wxHTML_SCROLL_STEP,
ScrollSteps(m_Cell->GetWidth(), clientWidth - vscrollbar),
ScrollSteps(m_Cell->GetHeight(), clientHeight)
);
}
}
}
#if wxUSE_CONFIG
void wxHtmlWindow::ReadCustomization(wxConfigBase *cfg, wxString path)
{
wxString oldpath;
wxString tmp;
int p_fontsizes[7];
wxString p_fff, p_ffn;
if (path != wxEmptyString)
{
oldpath = cfg->GetPath();
cfg->SetPath(path);
}
m_Borders = cfg->Read(wxT("wxHtmlWindow/Borders"), m_Borders);
p_fff = cfg->Read(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser->m_FontFaceFixed);
p_ffn = cfg->Read(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser->m_FontFaceNormal);
for (int i = 0; i < 7; i++)
{
tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
p_fontsizes[i] = cfg->Read(tmp, m_Parser->m_FontsSizes[i]);
}
SetFonts(p_ffn, p_fff, p_fontsizes);
if (path != wxEmptyString)
cfg->SetPath(oldpath);
}
void wxHtmlWindow::WriteCustomization(wxConfigBase *cfg, wxString path)
{
wxString oldpath;
wxString tmp;
if (path != wxEmptyString)
{
oldpath = cfg->GetPath();
cfg->SetPath(path);
}
cfg->Write(wxT("wxHtmlWindow/Borders"), (long) m_Borders);
cfg->Write(wxT("wxHtmlWindow/FontFaceFixed"), m_Parser->m_FontFaceFixed);
cfg->Write(wxT("wxHtmlWindow/FontFaceNormal"), m_Parser->m_FontFaceNormal);
for (int i = 0; i < 7; i++)
{
tmp.Printf(wxT("wxHtmlWindow/FontsSize%i"), i);
cfg->Write(tmp, (long) m_Parser->m_FontsSizes[i]);
}
if (path != wxEmptyString)
cfg->SetPath(oldpath);
}
#endif // wxUSE_CONFIG
bool wxHtmlWindow::HistoryBack()
{
wxString a, l;
if (m_HistoryPos < 1) return false;
// store scroll position into history item:
int x, y;
GetViewStart(&x, &y);
(*m_History)[m_HistoryPos].SetPos(y);
// go to previous position:
m_HistoryPos--;
l = (*m_History)[m_HistoryPos].GetPage();
a = (*m_History)[m_HistoryPos].GetAnchor();
m_HistoryOn = false;
m_tmpCanDrawLocks++;
if (a == wxEmptyString) LoadPage(l);
else LoadPage(l + wxT("#") + a);
m_HistoryOn = true;
m_tmpCanDrawLocks--;
Scroll(0, (*m_History)[m_HistoryPos].GetPos());
Refresh();
return true;
}
bool wxHtmlWindow::HistoryCanBack()
{
if (m_HistoryPos < 1) return false;
return true ;
}
bool wxHtmlWindow::HistoryForward()
{
wxString a, l;
if (m_HistoryPos == -1) return false;
if (m_HistoryPos >= (int)m_History->GetCount() - 1)return false;
m_OpenedPage = wxEmptyString; // this will disable adding new entry into history in LoadPage()
m_HistoryPos++;
l = (*m_History)[m_HistoryPos].GetPage();
a = (*m_History)[m_HistoryPos].GetAnchor();
m_HistoryOn = false;
m_tmpCanDrawLocks++;
if (a == wxEmptyString) LoadPage(l);
else LoadPage(l + wxT("#") + a);
m_HistoryOn = true;
m_tmpCanDrawLocks--;
Scroll(0, (*m_History)[m_HistoryPos].GetPos());
Refresh();
return true;
}
bool wxHtmlWindow::HistoryCanForward()
{
if (m_HistoryPos == -1) return false;
if (m_HistoryPos >= (int)m_History->GetCount() - 1)return false;
return true ;
}
void wxHtmlWindow::HistoryClear()
{
m_History->Empty();
m_HistoryPos = -1;
}
void wxHtmlWindow::AddProcessor(wxHtmlProcessor *processor)
{
if (!m_Processors)
{
m_Processors = new wxHtmlProcessorList;
}
wxHtmlProcessorList::compatibility_iterator node;
for (node = m_Processors->GetFirst(); node; node = node->GetNext())
{
if (processor->GetPriority() > node->GetData()->GetPriority())
{
m_Processors->Insert(node, processor);
return;
}
}
m_Processors->Append(processor);
}
/*static */ void wxHtmlWindow::AddGlobalProcessor(wxHtmlProcessor *processor)
{
if (!m_GlobalProcessors)
{
m_GlobalProcessors = new wxHtmlProcessorList;
}
wxHtmlProcessorList::compatibility_iterator node;
for (node = m_GlobalProcessors->GetFirst(); node; node = node->GetNext())
{
if (processor->GetPriority() > node->GetData()->GetPriority())
{
m_GlobalProcessors->Insert(node, processor);
return;
}
}
m_GlobalProcessors->Append(processor);
}
void wxHtmlWindow::AddFilter(wxHtmlFilter *filter)
{
m_Filters.Append(filter);
}
bool wxHtmlWindow::IsSelectionEnabled() const
{
#if wxUSE_CLIPBOARD
return !HasFlag(wxHW_NO_SELECTION);
#else
return false;
#endif
}
#if wxUSE_CLIPBOARD
wxString wxHtmlWindow::DoSelectionToText(wxHtmlSelection *sel)
{
if ( !sel )
return wxEmptyString;
wxClientDC dc(this);
wxString text;
wxHtmlTerminalCellsInterator i(sel->GetFromCell(), sel->GetToCell());
const wxHtmlCell *prev = NULL;
while ( i )
{
// When converting HTML content to plain text, the entire paragraph
// (container in wxHTML) goes on single line. A new paragraph (that
// should go on its own line) has its own container. Therefore, the
// simplest way of detecting where to insert newlines in plain text
// is to check if the parent container changed -- if it did, we moved
// to a new paragraph.
if ( prev && prev->GetParent() != i->GetParent() )
text << '\n';
// NB: we don't need to pass the selection to ConvertToText() in the
// middle of the selected text; it's only useful when only part of
// a cell is selected
text << i->ConvertToText(sel);
prev = *i;
++i;
}
return text;
}
wxString wxHtmlWindow::ToText()
{
if (m_Cell)
{
wxHtmlSelection sel;
sel.Set(m_Cell->GetFirstTerminal(), m_Cell->GetLastTerminal());
return DoSelectionToText(&sel);
}
else
return wxEmptyString;
}
#endif // wxUSE_CLIPBOARD
bool wxHtmlWindow::CopySelection(ClipboardType t)
{
#if wxUSE_CLIPBOARD
if ( m_selection )
{
#if defined(__UNIX__) && !defined(__WXMAC__)
wxTheClipboard->UsePrimarySelection(t == Primary);
#else // !__UNIX__
// Primary selection exists only under X11, so don't do anything under
// the other platforms when we try to access it
//
// TODO: this should be abstracted at wxClipboard level!
if ( t == Primary )
return false;
#endif // __UNIX__/!__UNIX__
if ( wxTheClipboard->Open() )
{
const wxString txt(SelectionToText());
wxTheClipboard->SetData(new wxTextDataObject(txt));
wxTheClipboard->Close();
wxLogTrace(wxT("wxhtmlselection"),
_("Copied to clipboard:\"%s\""), txt.c_str());
return true;
}
}
#else
wxUnusedVar(t);
#endif // wxUSE_CLIPBOARD
return false;
}
void wxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link)
{
wxHtmlLinkEvent event(GetId(), link);
event.SetEventObject(this);
if (!GetEventHandler()->ProcessEvent(event))
{
// the default behaviour is to load the URL in this window
const wxMouseEvent *e = event.GetLinkInfo().GetEvent();
if (e == NULL || e->LeftUp())
LoadPage(event.GetLinkInfo().GetHref());
}
}
void wxHtmlWindow::DoEraseBackground(wxDC& dc)
{
// if we don't have any background bitmap we just fill it with background
// colour and we also must do it if the background bitmap is not fully
// opaque as otherwise junk could be left there
if ( !m_bmpBg.IsOk() || m_bmpBg.GetMask() )
{
dc.SetBackground(GetBackgroundColour());
dc.Clear();
}
if ( m_bmpBg.IsOk() )
{
// draw the background bitmap tiling it over the entire window area
const wxSize sz = GetClientSize();
const wxSize sizeBmp(m_bmpBg.GetWidth(), m_bmpBg.GetHeight());
for ( wxCoord x = 0; x < sz.x; x += sizeBmp.x )
{
for ( wxCoord y = 0; y < sz.y; y += sizeBmp.y )
{
dc.DrawBitmap(m_bmpBg, x, y, true /* use mask */);
}
}
}
}
void wxHtmlWindow::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
{
// We never get real erase background events as we changed our background
// style to wxBG_STYLE_PAINT in our ctor so the only time when we get here
// is when an artificial wxEraseEvent is generated by our own OnPaint()
// below. This handler only exists to stop the event from propagating
// downwards to wxWindow which may erase the background itself when it gets
// it in some ports (currently this happens in wxUniv), so we simply stop
// processing here and set a special flag allowing OnPaint() to see that
// the event hadn't been really processed.
m_isBgReallyErased = false;
}
void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dcPaint(this);
if (m_tmpCanDrawLocks > 0 || m_Cell == NULL)
return;
int x, y;
GetViewStart(&x, &y);
const wxRect rect = GetUpdateRegion().GetBox();
const wxSize sz = GetClientSize();
// set up the DC we're drawing on: if the window is already double buffered
// we do it directly on wxPaintDC, otherwise we allocate a backing store
// buffer and compose the drawing there and then blit it to screen all at
// once
wxDC *dc;
wxMemoryDC dcm;
if ( IsDoubleBuffered() )
{
dc = &dcPaint;
}
else // window is not double buffered by the system, do it ourselves
{
if ( !m_backBuffer.IsOk() )
m_backBuffer.Create(sz.x, sz.y);
dcm.SelectObject(m_backBuffer);
dc = &dcm;
}
PrepareDC(*dc);
// Erase the background: for compatibility, we must generate the event to
// allow the user-defined handlers to do it, hence this hack with sending
// an artificial wxEraseEvent to trigger the execution of such handlers.
wxEraseEvent eraseEvent(GetId(), dc);
eraseEvent.SetEventObject(this);
// Hack inside a hack: the background wasn't really erased if our own
// OnEraseBackground() was executed, so we need to check for the flag set
// by it whenever it's called.
m_isBgReallyErased = true; // Initially assume it wasn't.
if ( !ProcessWindowEvent(eraseEvent) || !m_isBgReallyErased )
{
// erase background ourselves
DoEraseBackground(*dc);
}
//else: background erased by the user-defined handler
// draw the HTML window contents
dc->SetMapMode(wxMM_TEXT);
dc->SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
dc->SetLayoutDirection(GetLayoutDirection());
wxHtmlRenderingInfo rinfo;
wxDefaultHtmlRenderingStyle rstyle;
rinfo.SetSelection(m_selection);
rinfo.SetStyle(&rstyle);
m_Cell->Draw(*dc, 0, 0,
y * wxHTML_SCROLL_STEP + rect.GetTop(),
y * wxHTML_SCROLL_STEP + rect.GetBottom(),
rinfo);
#ifdef DEBUG_HTML_SELECTION
{
int xc, yc, x, y;
wxGetMousePosition(&xc, &yc);
ScreenToClient(&xc, &yc);
CalcUnscrolledPosition(xc, yc, &x, &y);
wxHtmlCell *at = m_Cell->FindCellByPos(x, y);
wxHtmlCell *before =
m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_BEFORE);
wxHtmlCell *after =
m_Cell->FindCellByPos(x, y, wxHTML_FIND_NEAREST_AFTER);
dc->SetBrush(*wxTRANSPARENT_BRUSH);
dc->SetPen(*wxBLACK_PEN);
if (at)
dc->DrawRectangle(at->GetAbsPos(),
wxSize(at->GetWidth(),at->GetHeight()));
dc->SetPen(*wxGREEN_PEN);
if (before)
dc->DrawRectangle(before->GetAbsPos().x+1, before->GetAbsPos().y+1,
before->GetWidth()-2,before->GetHeight()-2);
dc->SetPen(*wxRED_PEN);
if (after)
dc->DrawRectangle(after->GetAbsPos().x+2, after->GetAbsPos().y+2,
after->GetWidth()-4,after->GetHeight()-4);
}
#endif // DEBUG_HTML_SELECTION
if ( dc != &dcPaint )
{
dc->SetDeviceOrigin(0,0);
dcPaint.Blit(0, rect.GetTop(),
sz.x, rect.GetBottom() - rect.GetTop() + 1,
dc,
0, rect.GetTop());
}
}
void wxHtmlWindow::OnSize(wxSizeEvent& event)
{
event.Skip();
m_backBuffer = wxNullBitmap;
CreateLayout();
// Recompute selection if necessary:
if ( m_selection )
{
m_selection->Set(m_selection->GetFromCell(),
m_selection->GetToCell());
m_selection->ClearFromToCharacterPos();
}
Refresh();
}
void wxHtmlWindow::OnMouseMove(wxMouseEvent& WXUNUSED(event))
{
wxHtmlWindowMouseHelper::HandleMouseMoved();
}
void wxHtmlWindow::OnMouseDown(wxMouseEvent& event)
{
#if wxUSE_CLIPBOARD
if ( event.LeftDown() && IsSelectionEnabled() )
{
const long TRIPLECLICK_LEN = 200; // 0.2 sec after doubleclick
if ( wxGetLocalTimeMillis() - m_lastDoubleClick <= TRIPLECLICK_LEN )
{
SelectLine(CalcUnscrolledPosition(event.GetPosition()));
(void) CopySelection();
}
else
{
m_makingSelection = true;
if ( m_selection )
{
wxDELETE(m_selection);
Refresh();
}
m_tmpSelFromPos = CalcUnscrolledPosition(event.GetPosition());
m_tmpSelFromCell = NULL;
CaptureMouse();
}
}
#endif // wxUSE_CLIPBOARD
// in any case, let the default handler set focus to this window
event.Skip();
}
void wxHtmlWindow::OnMouseUp(wxMouseEvent& event)
{
#if wxUSE_CLIPBOARD
if ( m_makingSelection )
{
ReleaseMouse();
m_makingSelection = false;
// if m_selection=NULL, the user didn't move the mouse far enough from
// starting point and the mouse up event is part of a click, the user
// is not selecting text:
if ( m_selection )
{
CopySelection(Primary);
// we don't want mouse up event that ended selecting to be
// handled as mouse click and e.g. follow hyperlink:
return;
}
}
#endif // wxUSE_CLIPBOARD
wxPoint pos = CalcUnscrolledPosition(event.GetPosition());
if ( !wxHtmlWindowMouseHelper::HandleMouseClick(m_Cell, pos, event) )
event.Skip();
}
#if wxUSE_CLIPBOARD
void wxHtmlWindow::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
{
if ( !m_makingSelection )
return;
// discard the selecting operation
m_makingSelection = false;
wxDELETE(m_selection);
m_tmpSelFromCell = NULL;
Refresh();
}
#endif // wxUSE_CLIPBOARD
void wxHtmlWindow::OnInternalIdle()
{
wxWindow::OnInternalIdle();
if (m_Cell != NULL && DidMouseMove())
{
#ifdef DEBUG_HTML_SELECTION
Refresh();
#endif
int xc, yc, x, y;
wxGetMousePosition(&xc, &yc);
ScreenToClient(&xc, &yc);
CalcUnscrolledPosition(xc, yc, &x, &y);
wxHtmlCell *cell = m_Cell->FindCellByPos(x, y);
// handle selection update:
if ( m_makingSelection )
{
if ( !m_tmpSelFromCell )
m_tmpSelFromCell = m_Cell->FindCellByPos(
m_tmpSelFromPos.x,m_tmpSelFromPos.y);
// NB: a trick - we adjust selFromPos to be upper left or bottom
// right corner of the first cell of the selection depending
// on whether the mouse is moving to the right or to the left.
// This gives us more "natural" behaviour when selecting
// a line (specifically, first cell of the next line is not
// included if you drag selection from left to right over
// entire line):
wxPoint dirFromPos;
if ( !m_tmpSelFromCell )
{
dirFromPos = m_tmpSelFromPos;
}
else
{
dirFromPos = m_tmpSelFromCell->GetAbsPos();
if ( x < m_tmpSelFromPos.x )
{
dirFromPos.x += m_tmpSelFromCell->GetWidth();
dirFromPos.y += m_tmpSelFromCell->GetHeight();
}
}
bool goingDown = dirFromPos.y < y ||
(dirFromPos.y == y && dirFromPos.x < x);
// determine selection span:
if ( /*still*/ !m_tmpSelFromCell )
{
if (goingDown)
{
m_tmpSelFromCell = m_Cell->FindCellByPos(
m_tmpSelFromPos.x,m_tmpSelFromPos.y,
wxHTML_FIND_NEAREST_AFTER);
if (!m_tmpSelFromCell)
m_tmpSelFromCell = m_Cell->GetFirstTerminal();
}
else
{
m_tmpSelFromCell = m_Cell->FindCellByPos(
m_tmpSelFromPos.x,m_tmpSelFromPos.y,
wxHTML_FIND_NEAREST_BEFORE);
if (!m_tmpSelFromCell)
m_tmpSelFromCell = m_Cell->GetLastTerminal();
}
}
wxHtmlCell *selcell = cell;
if (!selcell)
{
if (goingDown)
{
selcell = m_Cell->FindCellByPos(x, y,
wxHTML_FIND_NEAREST_BEFORE);
if (!selcell)
selcell = m_Cell->GetLastTerminal();
}
else
{
selcell = m_Cell->FindCellByPos(x, y,
wxHTML_FIND_NEAREST_AFTER);
if (!selcell)
selcell = m_Cell->GetFirstTerminal();
}
}
// NB: it may *rarely* happen that the code above didn't find one
// of the cells, e.g. if wxHtmlWindow doesn't contain any
// visible cells.
if ( selcell && m_tmpSelFromCell )
{
if ( !m_selection )
{
// start selecting only if mouse movement was big enough
// (otherwise it was meant as mouse click, not selection):
const int PRECISION = 2;
wxPoint diff = m_tmpSelFromPos - wxPoint(x,y);
if (abs(diff.x) > PRECISION || abs(diff.y) > PRECISION)
{
m_selection = new wxHtmlSelection();
}
}
if ( m_selection )
{
if ( m_tmpSelFromCell->IsBefore(selcell) )
{
m_selection->Set(m_tmpSelFromPos, m_tmpSelFromCell,
wxPoint(x,y), selcell);
}
else
{
m_selection->Set(wxPoint(x,y), selcell,
m_tmpSelFromPos, m_tmpSelFromCell);
}
m_selection->ClearFromToCharacterPos();
Refresh();
}
}
}
// handle cursor and status bar text changes:
// NB: because we're passing in 'cell' and not 'm_Cell' (so that the
// leaf cell lookup isn't done twice), we need to adjust the
// position for the new root:
wxPoint posInCell(x, y);
if (cell)
posInCell -= cell->GetAbsPos();
wxHtmlWindowMouseHelper::HandleIdle(cell, posInCell);
}
}
#if wxUSE_CLIPBOARD
void wxHtmlWindow::StopAutoScrolling()
{
if ( m_timerAutoScroll )
{
wxDELETE(m_timerAutoScroll);
}
}
void wxHtmlWindow::OnMouseEnter(wxMouseEvent& event)
{
StopAutoScrolling();
event.Skip();
}
void wxHtmlWindow::OnMouseLeave(wxMouseEvent& event)
{
// don't prevent the usual processing of the event from taking place
event.Skip();
// when a captured mouse leave a scrolled window we start generate
// scrolling events to allow, for example, extending selection beyond the
// visible area in some controls
if ( wxWindow::GetCapture() == this )
{
// where is the mouse leaving?
int pos, orient;
wxPoint pt = event.GetPosition();
if ( pt.x < 0 )
{
orient = wxHORIZONTAL;
pos = 0;
}
else if ( pt.y < 0 )
{
orient = wxVERTICAL;
pos = 0;
}
else // we're lower or to the right of the window
{
wxSize size = GetClientSize();
if ( pt.x > size.x )
{
orient = wxHORIZONTAL;
pos = GetVirtualSize().x / wxHTML_SCROLL_STEP;
}
else if ( pt.y > size.y )
{
orient = wxVERTICAL;
pos = GetVirtualSize().y / wxHTML_SCROLL_STEP;
}
else // this should be impossible
{
// but seems to happen sometimes under wxMSW - maybe it's a bug
// there but for now just ignore it
//wxFAIL_MSG( wxT("can't understand where has mouse gone") );
return;
}
}
// only start the auto scroll timer if the window can be scrolled in
// this direction
if ( !HasScrollbar(orient) )
return;
delete m_timerAutoScroll;
m_timerAutoScroll = new wxHtmlWinAutoScrollTimer
(
this,
pos == 0 ? wxEVT_SCROLLWIN_LINEUP
: wxEVT_SCROLLWIN_LINEDOWN,
pos,
orient
);
m_timerAutoScroll->Start(50); // FIXME: make configurable
}
}
void wxHtmlWindow::OnKeyUp(wxKeyEvent& event)
{
if ( IsSelectionEnabled() &&
(event.GetKeyCode() == 'C' && event.CmdDown()) )
{
wxClipboardTextEvent evt(wxEVT_COMMAND_TEXT_COPY, GetId());
evt.SetEventObject(this);
GetEventHandler()->ProcessEvent(evt);
}
else
{
event.Skip();
}
}
void wxHtmlWindow::OnCopy(wxCommandEvent& WXUNUSED(event))
{
(void) CopySelection();
}
void wxHtmlWindow::OnClipboardEvent(wxClipboardTextEvent& WXUNUSED(event))
{
(void) CopySelection();
}
void wxHtmlWindow::OnDoubleClick(wxMouseEvent& event)
{
// select word under cursor:
if ( IsSelectionEnabled() )
{
SelectWord(CalcUnscrolledPosition(event.GetPosition()));
(void) CopySelection(Primary);
m_lastDoubleClick = wxGetLocalTimeMillis();
}
else
event.Skip();
}
void wxHtmlWindow::SelectWord(const wxPoint& pos)
{
if ( m_Cell )
{
wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
if ( cell )
{
delete m_selection;
m_selection = new wxHtmlSelection();
m_selection->Set(cell, cell);
RefreshRect(wxRect(CalcScrolledPosition(cell->GetAbsPos()),
wxSize(cell->GetWidth(), cell->GetHeight())));
}
}
}
void wxHtmlWindow::SelectLine(const wxPoint& pos)
{
if ( m_Cell )
{
wxHtmlCell *cell = m_Cell->FindCellByPos(pos.x, pos.y);
if ( cell )
{
// We use following heuristic to find a "line": let the line be all
// cells in same container as the cell under mouse cursor that are
// neither completely above nor completely below the clicked cell
// (i.e. are likely to be words positioned on same line of text).
int y1 = cell->GetAbsPos().y;
int y2 = y1 + cell->GetHeight();
int y;
const wxHtmlCell *c;
const wxHtmlCell *before = NULL;
const wxHtmlCell *after = NULL;
// find last cell of line:
for ( c = cell->GetNext(); c; c = c->GetNext())
{
y = c->GetAbsPos().y;
if ( y + c->GetHeight() > y1 && y < y2 )
after = c;
else
break;
}
if ( !after )
after = cell;
// find first cell of line:
for ( c = cell->GetParent()->GetFirstChild();
c && c != cell; c = c->GetNext())
{
y = c->GetAbsPos().y;
if ( y + c->GetHeight() > y1 && y < y2 )
{
if ( ! before )
before = c;
}
else
before = NULL;
}
if ( !before )
before = cell;
delete m_selection;
m_selection = new wxHtmlSelection();
m_selection->Set(before, after);
Refresh();
}
}
}
void wxHtmlWindow::SelectAll()
{
if ( m_Cell )
{
delete m_selection;
m_selection = new wxHtmlSelection();
m_selection->Set(m_Cell->GetFirstTerminal(), m_Cell->GetLastTerminal());
Refresh();
}
}
#endif // wxUSE_CLIPBOARD
IMPLEMENT_ABSTRACT_CLASS(wxHtmlProcessor,wxObject)
wxBEGIN_PROPERTIES_TABLE(wxHtmlWindow)
/*
TODO PROPERTIES
style , wxHW_SCROLLBAR_AUTO
borders , (dimension)
url , string
htmlcode , string
*/
wxEND_PROPERTIES_TABLE()
wxBEGIN_HANDLERS_TABLE(wxHtmlWindow)
wxEND_HANDLERS_TABLE()
wxCONSTRUCTOR_5( wxHtmlWindow , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle )
wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxHtmlWindow, wxScrolledWindow,"wx/html/htmlwin.h")
BEGIN_EVENT_TABLE(wxHtmlWindow, wxScrolledWindow)
EVT_SIZE(wxHtmlWindow::OnSize)
EVT_LEFT_DOWN(wxHtmlWindow::OnMouseDown)
EVT_LEFT_UP(wxHtmlWindow::OnMouseUp)
EVT_RIGHT_UP(wxHtmlWindow::OnMouseUp)
EVT_MOTION(wxHtmlWindow::OnMouseMove)
EVT_PAINT(wxHtmlWindow::OnPaint)
EVT_ERASE_BACKGROUND(wxHtmlWindow::OnEraseBackground)
#if wxUSE_CLIPBOARD
EVT_LEFT_DCLICK(wxHtmlWindow::OnDoubleClick)
EVT_ENTER_WINDOW(wxHtmlWindow::OnMouseEnter)
EVT_LEAVE_WINDOW(wxHtmlWindow::OnMouseLeave)
EVT_MOUSE_CAPTURE_LOST(wxHtmlWindow::OnMouseCaptureLost)
EVT_KEY_UP(wxHtmlWindow::OnKeyUp)
EVT_MENU(wxID_COPY, wxHtmlWindow::OnCopy)
EVT_TEXT_COPY(wxID_ANY, wxHtmlWindow::OnClipboardEvent)
#endif // wxUSE_CLIPBOARD
END_EVENT_TABLE()
//-----------------------------------------------------------------------------
// wxHtmlWindowInterface implementation in wxHtmlWindow
//-----------------------------------------------------------------------------
void wxHtmlWindow::SetHTMLWindowTitle(const wxString& title)
{
OnSetTitle(title);
}
void wxHtmlWindow::OnHTMLLinkClicked(const wxHtmlLinkInfo& link)
{
OnLinkClicked(link);
}
wxHtmlOpeningStatus wxHtmlWindow::OnHTMLOpeningURL(wxHtmlURLType type,
const wxString& url,
wxString *redirect) const
{
return OnOpeningURL(type, url, redirect);
}
wxPoint wxHtmlWindow::HTMLCoordsToWindow(wxHtmlCell *WXUNUSED(cell),
const wxPoint& pos) const
{
return CalcScrolledPosition(pos);
}
wxWindow* wxHtmlWindow::GetHTMLWindow()
{
return this;
}
wxColour wxHtmlWindow::GetHTMLBackgroundColour() const
{
return GetBackgroundColour();
}
void wxHtmlWindow::SetHTMLBackgroundColour(const wxColour& clr)
{
SetBackgroundColour(clr);
}
void wxHtmlWindow::SetHTMLBackgroundImage(const wxBitmap& bmpBg)
{
SetBackgroundImage(bmpBg);
}
void wxHtmlWindow::SetHTMLStatusText(const wxString& text)
{
#if wxUSE_STATUSBAR
if (m_RelatedStatusBarIndex != -1)
{
if (m_RelatedStatusBar)
{
m_RelatedStatusBar->SetStatusText(text, m_RelatedStatusBarIndex);
}
else if (m_RelatedFrame)
{
m_RelatedFrame->SetStatusText(text, m_RelatedStatusBarIndex);
}
}
#else
wxUnusedVar(text);
#endif // wxUSE_STATUSBAR
}
/*static*/
wxCursor wxHtmlWindow::GetDefaultHTMLCursor(HTMLCursor type)
{
switch (type)
{
case HTMLCursor_Link:
if ( !ms_cursorLink )
ms_cursorLink = new wxCursor(wxCURSOR_HAND);
return *ms_cursorLink;
case HTMLCursor_Text:
if ( !ms_cursorText )
ms_cursorText = new wxCursor(wxCURSOR_IBEAM);
return *ms_cursorText;
case HTMLCursor_Default:
default:
return *wxSTANDARD_CURSOR;
}
}
wxCursor wxHtmlWindow::GetHTMLCursor(HTMLCursor type) const
{
return GetDefaultHTMLCursor(type);
}
//-----------------------------------------------------------------------------
// wxHtmlWinModule
//-----------------------------------------------------------------------------
// A module to allow initialization/cleanup
// without calling these functions from app.cpp or from
// the user's application.
class wxHtmlWinModule: public wxModule
{
DECLARE_DYNAMIC_CLASS(wxHtmlWinModule)
public:
wxHtmlWinModule() : wxModule() {}
bool OnInit() { return true; }
void OnExit() { wxHtmlWindow::CleanUpStatics(); }
};
IMPLEMENT_DYNAMIC_CLASS(wxHtmlWinModule, wxModule)
// This hack forces the linker to always link in m_* files
// (wxHTML doesn't work without handlers from these files)
#include "wx/html/forcelnk.h"
FORCE_WXHTML_MODULES()
#endif // wxUSE_HTML