htmlwin.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,495 行 · 第 1/3 页

CPP
1,495
字号
/////////////////////////////////////////////////////////////////////////////
// Name:        htmlwin.cpp
// Purpose:     wxHtmlWindow class for parsing & displaying HTML (implementation)
// Author:      Vaclav Slavik
// RCS-ID:      $Id: htmlwin.cpp,v 1.109.2.1 2006/01/18 16:48:40 VZ Exp $
// Copyright:   (c) 1999 Vaclav Slavik
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////


#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "htmlwin.h"
#pragma implementation "htmlproc.h"
#endif

#include "wx/wxprec.h"

#include "wx/defs.h"
#if wxUSE_HTML && wxUSE_STREAMS

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WXPRECOMP
    #include "wx/log.h"
    #include "wx/intl.h"
    #include "wx/dcclient.h"
    #include "wx/frame.h"
#endif

#include "wx/html/htmlwin.h"
#include "wx/html/htmlproc.h"
#include "wx/list.h"
#include "wx/clipbrd.h"
#include "wx/dataobj.h"
#include "wx/timer.h"
#include "wx/dcmemory.h"
#include "wx/settings.h"

#include "wx/arrimpl.cpp"
#include "wx/listimpl.cpp"


#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;

    DECLARE_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);

//-----------------------------------------------------------------------------
// wxHtmlWindow
//-----------------------------------------------------------------------------


void wxHtmlWindow::Init()
{
    m_tmpMouseMoved = false;
    m_tmpLastLink = NULL;
    m_tmpLastCell = NULL;
    m_tmpCanDrawLocks = 0;
    m_FS = new wxFileSystem();
#if wxUSE_STATUSBAR
    m_RelatedStatusBar = -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;
    m_Style = 0;
    SetBorders(10);
    m_selection = NULL;
    m_makingSelection = false;
#if wxUSE_CLIPBOARD
    m_timerAutoScroll = NULL;
    m_lastDoubleClick = 0;
#endif // wxUSE_CLIPBOARD
    m_backBuffer = NULL;
    m_eraseBgInOnPaint = false;
    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;

    m_Style = style;
    SetPage(wxT("<html><body></body></html>"));
    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;
    delete m_backBuffer;
}



void wxHtmlWindow::SetRelatedFrame(wxFrame* frame, const wxString& format)
{
    m_RelatedFrame = frame;
    m_TitleFormat = format;
}



#if wxUSE_STATUSBAR
void wxHtmlWindow::SetRelatedStatusBar(int bar)
{
    m_RelatedStatusBar = bar;
}
#endif // wxUSE_STATUSBAR



void wxHtmlWindow::SetFonts(wxString normal_face, wxString fixed_face, const int *sizes)
{
    wxString op = m_OpenedPage;

    m_Parser->SetFonts(normal_face, fixed_face, sizes);
    // fonts changed => contents invalid, so reload the page:
    SetPage(wxT("<html><body></body></html>"));
    if (!op.empty())
        LoadPage(op);
}

void wxHtmlWindow::SetStandardFonts(int size,
                                    const wxString& normal_face,
                                    const wxString& fixed_face)
{
    wxString op = m_OpenedPage;

    m_Parser->SetStandardFonts(size, normal_face, fixed_face);
    // fonts changed => contents invalid, so reload the page:
    SetPage(wxT("<html><body></body></html>"));
    if (!op.empty())
        LoadPage(op);
}


bool wxHtmlWindow::SetPage(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;

        nodeL = (m_Processors) ? m_Processors->GetFirst() : wxHtmlProcessorList::compatibility_iterator();
        nodeG = (m_GlobalProcessors) ? m_GlobalProcessors->GetFirst() : wxHtmlProcessorList::compatibility_iterator();

        // 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_OpenedPage = m_OpenedAnchor = m_OpenedPageTitle = wxEmptyString;
    m_Parser->SetDC(dc);
    if (m_Cell)
    {
        delete m_Cell;
        m_Cell = NULL;
    }
    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 SetPage(*(GetParser()->GetSource()) + source);
}

bool wxHtmlWindow::LoadPage(const wxString& location)
{
    wxBusyCursor busyCursor;

    wxFSFile *f;
    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);
    }

    if (location[0] == wxT('#'))
    {
        // local anchor:
        wxString anch = location.Mid(1) /*1 to end*/;
        m_tmpCanDrawLocks--;
        rt_val = ScrollToAnchor(anch);
        m_tmpCanDrawLocks++;
    }
    else if (location.Find(wxT('#')) != wxNOT_FOUND && location.BeforeFirst(wxT('#')) == m_OpenedPage)
    {
        wxString anch = location.AfterFirst(wxT('#'));
        m_tmpCanDrawLocks--;
        rt_val = ScrollToAnchor(anch);
        m_tmpCanDrawLocks++;
    }
    else if (location.Find(wxT('#')) != wxNOT_FOUND &&
             (m_FS->GetPath() + location.BeforeFirst(wxT('#'))) == m_OpenedPage)
    {
        wxString anch = location.AfterFirst(wxT('#'));
        m_tmpCanDrawLocks--;
        rt_val = ScrollToAnchor(anch);
        m_tmpCanDrawLocks++;
    }

    else
    {
        needs_refresh = true;
#if wxUSE_STATUSBAR
        // load&display it:
        if (m_RelatedStatusBar != -1)
        {
            m_RelatedFrame->SetStatusText(_("Connecting..."), m_RelatedStatusBar);
            Refresh(false);
        }
#endif // wxUSE_STATUSBAR

        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--;
            return false;
        }

        else
        {
            wxList::compatibility_iterator node;
            wxString src = wxEmptyString;

#if wxUSE_STATUSBAR
            if (m_RelatedStatusBar != -1)
            {
                wxString msg = _("Loading : ") + location;
                m_RelatedFrame->SetStatusText(msg, m_RelatedStatusBar);
                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_RelatedStatusBar != -1)
                m_RelatedFrame->SetStatusText(_("Done"), m_RelatedStatusBar);
#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;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?