diff --git a/src/Accelerators.cpp b/src/Accelerators.cpp index 7e08b916..afa71a95 100644 --- a/src/Accelerators.cpp +++ b/src/Accelerators.cpp @@ -14,6 +14,8 @@ #include "tmAction.h" #include "tmBundle.h" +#include "AcceleratorsDialog.h" + wxString normalize(wxString str) { str.Replace(wxT("&"), wxT("")); return str.Trim().MakeLower(); @@ -23,6 +25,24 @@ bool IsChord(wxString& accel) { return accel.Trim().Find(' ') != wxNOT_FOUND; } +bool shouldIgnore(int code) { + switch(code) { + case WXK_CONTROL: + case WXK_ALT: + case WXK_SHIFT: + case WXK_WINDOWS_LEFT: + case WXK_WINDOWS_RIGHT: + return true; + } + + return false; +} + +/** + * For constant time access, each keystroke is mapped to an int. + * The first 8 bits are used to store the modifiers. + * The remaining 24 bits are used to store the actual wxKeyCode of the key to press. + */ int makeHash(wxString& accel) { int code, flags; wxAcceleratorEntry::ParseAccel(wxT("\t")+accel, &flags, &code); @@ -45,21 +65,26 @@ KeyBinding::KeyBinding(wxMenuItem* menuItem) : menuItem(menuItem) { id = menuItem->GetId(); } -KeyChord::KeyChord(wxString chord) : key(chord) { } - Accelerators::Accelerators(EditorFrame* editorFrame) : m_editorFrame(editorFrame), m_activeChord(NULL), m_activeBundleChord(NULL) { ReadCustomShortcuts(); Reset(); } +/** + * Traverses the menubar. + * For each menu item, it grabs the binding from the menu + * and it checks if there is a custom binding for that menu item. + */ void Accelerators::ParseMenu() { m_chords.clear(); m_bindings.clear(); + m_needDefault = m_defaultBindings.size() == 0; + wxMenuBar* menuBar = m_editorFrame->GetMenuBar(); if(!menuBar) return; - + const unsigned int bundles = menuBar->FindMenu(_("&Bundles")); for(unsigned int c = 0; c < menuBar->GetMenuCount(); c++) { if(c == bundles) ParseBundlesMenu(menuBar->GetMenu(c)); @@ -91,6 +116,18 @@ void Accelerators::ParseMenu(wxMenuItem* item) { } else { label = text.Mid(0, tab); accel = text.Mid(tab+1); + + if(m_needDefault) { + m_defaultBindings[label] = accel; + } else { + // When reloading the accelerators, if the user removes a custom accelerator, it needs to reset to the original value + map::iterator iterator; + iterator = m_defaultBindings.find(normalize(label)); + if(iterator != m_defaultBindings.end()) { + accel = iterator->second; + } + + } } // now check if there is a custom shortcut @@ -138,6 +175,10 @@ void Accelerators::InsertBinding(wxMenuItem* item, wxString& accel) { } } +/** + * Traverses the bundles menu. + * For bundle menu items, their bindings are stored differently from other wxMenuItems + */ void Accelerators::ParseBundlesMenu(wxMenu* menu) { wxMenuItemList& items = menu->GetMenuItems(); for(unsigned int c = 0; c < items.size(); c++) { @@ -166,7 +207,8 @@ void Accelerators::ParseBundlesMenu(wxMenuItem* item) { if(iterator != m_customBindings.end()) { wxString accel = iterator->second.Trim(); bItem->SetCustomAccel(accel); - //InsertBinding(item, accel); + } else { + bItem->SetCustomAccel(wxT("")); } } @@ -192,24 +234,35 @@ void Accelerators::ReadCustomShortcuts() { return; } - wxArrayString keys = jsonRoot.GetMemberNames(); + if(!jsonRoot.HasMember(wxT("bindings"))) return; + wxJSONValue bindings = jsonRoot[wxT("bindings")]; + + m_customBindings.clear(); + wxArrayString keys = bindings.GetMemberNames(); for(unsigned int c = 0; c < keys.size(); c++) { wxString key = keys[c]; - m_customBindings[normalize(key)] = jsonRoot[key].AsString(); + m_customBindings[normalize(key)] = bindings[key].AsString(); } } -bool shouldIgnore(int code) { - switch(code) { - case WXK_CONTROL: - case WXK_ALT: - case WXK_SHIFT: - case WXK_WINDOWS_LEFT: - case WXK_WINDOWS_RIGHT: - return true; +void Accelerators::SaveCustomShortcuts(wxString& jsonString) { + wxJSONReader reader; + wxJSONValue bindings; + reader.Parse(jsonString, &bindings); + + wxJSONValue root; + root[wxT("bindings")] = bindings; + + wxString path = eGetSettings().GetSettingsDir() + wxT("accelerators.cfg"); + wxFileOutputStream fstream(path); + if (!fstream.IsOk()) { + wxMessageBox(_("Could not open accelerators settings file."), _("File error"), wxICON_ERROR|wxOK); + return; } - return false; + // Write settings + wxJSONWriter writer(wxJSONWRITER_STYLED); + writer.Write(root, fstream); } bool Accelerators::HandleKeyEvent(wxKeyEvent& event) { @@ -375,6 +428,9 @@ void Accelerators::Reset() { m_actionReturned = false; m_searchBundleBindings = false; m_searchBundleChords = false; + + m_bundleChords.clear(); + m_bundleBindings.clear(); } /** @@ -396,6 +452,9 @@ bool Accelerators::WasChordActivated() { return ret; } +/** + * Finds the menu item that matches the given key bidning hash and runs its event. + */ bool Accelerators::MatchMenus(int hash) { if(m_activeChord) { std::map::iterator iterator; diff --git a/src/Accelerators.h b/src/Accelerators.h index 58798fef..40965ed0 100644 --- a/src/Accelerators.h +++ b/src/Accelerators.h @@ -8,6 +8,7 @@ class EditorFrame; class tmAction; int makeHash(wxString& accel); +wxString normalize(wxString str); class KeyBinding { public: @@ -20,7 +21,7 @@ class KeyBinding { class KeyChord { public: - KeyChord(wxString chord); + KeyChord(wxString chord) : key(chord) {} wxString key; std::map bindings; @@ -41,6 +42,7 @@ class Accelerators { Accelerators(EditorFrame* editorFrame); void ReadCustomShortcuts(); + void SaveCustomShortcuts(wxString& jsonRoot); void ParseMenu(); void ParseMenu(wxMenu* menu); @@ -64,9 +66,11 @@ class Accelerators { wxString StatusBarText(); + std::map m_customBindings; + std::map m_defaultBindings; + private: EditorFrame* m_editorFrame; - std::map m_customBindings; std::map m_chords; std::map m_bindings; @@ -80,6 +84,7 @@ class Accelerators { bool m_actionReturned; bool m_searchBundleBindings; bool m_searchBundleChords; + bool m_needDefault; }; #endif diff --git a/src/AcceleratorsDialog.cpp b/src/AcceleratorsDialog.cpp new file mode 100644 index 00000000..d0aa3160 --- /dev/null +++ b/src/AcceleratorsDialog.cpp @@ -0,0 +1,224 @@ +/******************************************************************************* + * + * Copyright (C) 2009, Alexander Stigsen, e-texteditor.com + * + * This software is licensed under the Open Company License as described + * in the file license.txt, which you should have received as part of this + * distribution. The terms are also available at http://opencompany.org/license. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ******************************************************************************/ + +#include "AcceleratorsDialog.h" +#include "Accelerators.h" +#include "eBrowser.h" +#include "EditorFrame.h" +#include "BundleMenu.h" +#include "tmAction.h" +#include "tmBundle.h" +#include "AcceleratorsDialogHtml.h" + +#include +#include +#include + +enum { + CTRL_ACCELERATORS_BROWSER +}; + + +BEGIN_EVENT_TABLE(AcceleratorsDialog, wxDialog) + EVT_HTMLWND_BEFORE_LOAD(CTRL_ACCELERATORS_BROWSER, AcceleratorsDialog::OnBeforeLoad) +END_EVENT_TABLE() + +/** + * This class lists every single menu item in e and allows the user to change the key binding for almost all of them. + * The gui was going to be too crazy to quickly create in wxwidgets, so I stuck with what I know. + * The class creates an html page with all of the menu items, and displays it. The user will hardly know they are using a website. + * When they click the save button, the bindings are transfered via json in the url. + */ +AcceleratorsDialog::AcceleratorsDialog(EditorFrame *parent): + m_editorFrame(parent), m_accelerators(parent->GetAccelerators()), + wxDialog ((wxWindow*)parent, wxID_ANY, wxEmptyString, wxDefaultPosition) +{ + SetTitle(_("Customize Keyboard Shortcuts")); + + m_browser = NewBrowser(this, CTRL_ACCELERATORS_BROWSER); + + // Create Layout + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + mainSizer->Add(m_browser->GetWindow(), 1, wxEXPAND); + + // The string has to be created on the heap. + // Otherwise, there would be 4 copies of the string on the stack at one time and it causes a segfault + wxString* html = GetHtml(); + //wxFile f(wxT("accel.html"), wxFile::write); + //f.Write(*html); + m_browser->LoadString(*html, false); + delete html; + + SetSizer(mainSizer); + SetSize(570, 580); + Centre(); +} + +wxString* AcceleratorsDialog::GetHtml() { + ParseMenu(); + + int size = 0; + for(unsigned int c = 0; c < m_htmlBits.GetCount(); c++) { + size += m_htmlBits[c].Len(); + } + + wxString* output = new wxString(); + output->Alloc(size); + + for(unsigned int c = 0; c < m_htmlBits.GetCount(); c++) { + output->Append(m_htmlBits[c]); + } + + wxString* html = AcceleratorsDialogHtml(); + html->Replace(wxT("$1"), *output); + + delete output; + return html; +} + +void AcceleratorsDialog::ParseMenu() { + m_htmlBits.clear(); + m_id = 0; + + m_htmlBits.Add(wxT("")); + + wxMenuBar* menuBar = m_editorFrame->GetMenuBar(); + if(!menuBar) return; + + for(unsigned int c = 0; c < menuBar->GetMenuCount(); c++) { + ParseMenu(menuBar->GetMenu(c), c, menuBar->GetMenuLabel(c), 0, 0); + } + + m_htmlBits.Add(wxT("
")); +} + +wxString evenOdd(int index) { + return (index % 2 == 0 ? wxT("odd") : wxT("even")); +} + +wxString& encode(wxString& str) { + str.Replace(wxT(">"), wxT(">")); + str.Replace(wxT("<"), wxT("<")); + str.Replace(wxT("&"), wxT("&")); + return str; +} + +void AcceleratorsDialog::ParseMenu(wxMenu* menu, int index, wxString label, int level, int parent) { + label.Replace(wxT("&"), wxT("")); + int id = ++m_id; + + wxString menuClass = wxT(" menu"); + menuClass << parent; + + wxString menuId = wxT("menu"); + menuId << id; + + wxString levelClass = wxT(" level"); + levelClass << level; + + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(encode(label)); + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("")); + + wxMenuItemList& items = menu->GetMenuItems(); + int ix = 0; + for(unsigned int c = 0; c < items.size(); c++) { + wxMenuItem* item = items[c]; + if(item->IsSeparator()) continue; + + if(item->IsSubMenu()) { + ParseMenu(item->GetSubMenu(), ix, item->GetLabel(), level+1, id); + } else { + ParseMenu(item, ix, level+1, id); + } + + ix++; + } +} + +void AcceleratorsDialog::ParseMenu(wxMenuItem* item, int index, int level, int parent) { + if(item->IsSeparator()) return; + map::iterator iterator; + + wxString label, accel = wxT(""), customAccel = wxT(""); + + const type_info& typeInfo = typeid(*item); + if(typeInfo == typeid(wxMenuItem)) { + // read the data from the menu item + wxString text = item->GetText(); + int tab = text.Find('\t'); + if(tab == wxNOT_FOUND) { + label = text; + } else { + label = text.Mid(0, tab); + accel = text.Mid(tab+1); + } + + iterator = m_accelerators->m_defaultBindings.find(label); + if(iterator != m_accelerators->m_defaultBindings.end()) { + accel = iterator->second; + } + } else { + BundleMenuItem* bItem = (BundleMenuItem*) item; + + label = bItem->GetLabel(); + accel = bItem->GetAction().key.shortcut; + + if(accel.empty()) return; + } + + // now check if there is a custom shortcut + iterator = m_accelerators->m_customBindings.find(normalize(label)); + if(iterator != m_accelerators->m_customBindings.end()) { + customAccel = iterator->second; + } + + label.Replace(wxT("&"), wxT("")); + accel = encode(accel.Trim()); + if(accel.Len() == 0) accel = wxT(" "); + customAccel = customAccel.Trim(); + + + wxString menuClass = wxT(" menu"); + menuClass << parent; + + wxString levelClass = wxT(" level"); + levelClass << level; + + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("") + encode(label) + wxT("")); + m_htmlBits.Add(wxT("") + accel + wxT("")); + m_htmlBits.Add(wxT("")); + m_htmlBits.Add(wxT("")); + +} + +void AcceleratorsDialog::OnBeforeLoad(IHtmlWndBeforeLoadEvent& event) { + wxString url = event.GetURL(); + if(url.StartsWith(wxT("about")) || url.StartsWith(wxT("javascript"))) return; + + wxString jsonString = wxURI::Unescape(url); + jsonString.Replace(wxT("http://localhost/"), wxT("")); + + m_accelerators->SaveCustomShortcuts(jsonString); + m_accelerators->ReadCustomShortcuts(); + m_accelerators->ParseMenu(); + + event.Cancel(); + this->Close(); +} \ No newline at end of file diff --git a/src/AcceleratorsDialog.h b/src/AcceleratorsDialog.h new file mode 100644 index 00000000..25f7ff2f --- /dev/null +++ b/src/AcceleratorsDialog.h @@ -0,0 +1,34 @@ +#ifndef __ACCELERATORSDLG_H__ +#define __ACCELERATORSDLG_H__ + +#include "wx/wxprec.h" +#ifndef WX_PRECOMP + #include +#endif + +class EditorFrame; +class Accelerators; +class IHtmlWnd; +class IHtmlWndBeforeLoadEvent; + +class AcceleratorsDialog : public wxDialog { +public: + AcceleratorsDialog(EditorFrame *parent); + + wxString* GetHtml(); + void ParseMenu(); + void ParseMenu(wxMenu* menuItem, int index, wxString label, int level, int parent); + void ParseMenu(wxMenuItem* menuItem, int index, int level, int parent); + +private: + void OnBeforeLoad(IHtmlWndBeforeLoadEvent& event); + + EditorFrame* m_editorFrame; + IHtmlWnd* m_browser; + wxArrayString m_htmlBits; + Accelerators* m_accelerators; + int m_id; + + DECLARE_EVENT_TABLE(); +}; +#endif // __ACCELERATORSDLG_H__ diff --git a/src/AcceleratorsDialog.html b/src/AcceleratorsDialog.html new file mode 100644 index 00000000..afe83c8f --- /dev/null +++ b/src/AcceleratorsDialog.html @@ -0,0 +1,323 @@ + + + + + + + +
+ $1 +
+
+ +
+ + + + \ No newline at end of file diff --git a/src/AcceleratorsDialogGenerator.rb b/src/AcceleratorsDialogGenerator.rb new file mode 100644 index 00000000..3a43b5ad --- /dev/null +++ b/src/AcceleratorsDialogGenerator.rb @@ -0,0 +1,20 @@ +name = "output" + +file = File.new('AcceleratorsDialog.html') +size = file.read.size + +file = File.new('AcceleratorsDialog.html') +str = file.read.gsub(/([\\\"])/) {|match| "\\#{match}"} +str = str.split("\n").map do |line| + "#{name}->Append(wxT(\"#{line}\\n\"));" +end.join("\n") + +output = "#include \"wx/wx.h\" +wxString* AcceleratorsDialogHtml() { + wxString* #{name} = new wxString(); + #{name}->Alloc(#{size}); + #{str} + return #{name}; +}" + +File.open('AcceleratorsDialogHtml.h', 'w+') {|file| file.write output } \ No newline at end of file diff --git a/src/AcceleratorsDialogHtml.h b/src/AcceleratorsDialogHtml.h new file mode 100644 index 00000000..6347d92b --- /dev/null +++ b/src/AcceleratorsDialogHtml.h @@ -0,0 +1,329 @@ +#include "wx/wx.h" +wxString* AcceleratorsDialogHtml() { + wxString* output = new wxString(); + output->Alloc(7137); + output->Append(wxT(" \n")); +output->Append(wxT(" \n")); +output->Append(wxT(" \n")); +output->Append(wxT(" \n")); +output->Append(wxT(" \n")); +output->Append(wxT("\n")); +output->Append(wxT("\n")); +output->Append(wxT("
\n")); +output->Append(wxT(" $1\n")); +output->Append(wxT("
\n")); +output->Append(wxT("
\n")); +output->Append(wxT(" \n")); +output->Append(wxT("
\n")); +output->Append(wxT("\n")); +output->Append(wxT("\n")); +output->Append(wxT("\n")); +output->Append(wxT("\n")); + return output; +} \ No newline at end of file diff --git a/src/EditorFrame.cpp b/src/EditorFrame.cpp index 8a95b3b0..75090ddc 100644 --- a/src/EditorFrame.cpp +++ b/src/EditorFrame.cpp @@ -72,6 +72,7 @@ #include "SnippetList.h" #include "ClipboardHistoryPane.h" #include "Accelerators.h" +#include "AcceleratorsDialog.h" #include "InputPanel.h" #ifdef __WXMSW__ @@ -297,6 +298,7 @@ BEGIN_EVENT_TABLE(EditorFrame, wxFrame) EVT_MENU(MENU_NAVIGATE_SELECTIONS_MODE, EditorFrame::OnMenuNavigateSelections) EVT_MENU(MENU_NAVIGATE_SELECTIONS_NEXT, EditorFrame::OnMenuNavigateSelectionsNext) EVT_MENU(MENU_NAVIGATE_SELECTIONS_PREVIOUS, EditorFrame::OnMenuNavigateSelectionsPrevious) + EVT_MENU(MENU_ACCELERATORS, EditorFrame::OnMenuCustomizeAccelerators) //EVT_MENU(MENU_DOC_OPEN, EditorFrame::OnMenuDocOpen) //EVT_MENU(MENU_DOC_SHARE, EditorFrame::OnMenuDocShare) @@ -645,6 +647,7 @@ void EditorFrame::InitMenus() { editMenu->AppendSeparator(); editMenu->Append(MENU_EDIT_THEME, _("Edit &Theme..."), _("Edit Theme")); editMenu->Append(MENU_SETTINGS, _("S&ettings..."), _("Edit Settings")); + editMenu->Append(MENU_ACCELERATORS, _("&Keyboard Shortcuts..."), _("Edit Keyboard Shortcuts")); menuBar->Append(editMenu, _("&Edit")); // View menu @@ -4223,3 +4226,7 @@ void EditorFrame::OnMenuNavigateSelectionsPrevious(wxCommandEvent& WXUNUSED(even bool EditorFrame::HandleChord(wxKeyEvent& event) { return m_accelerators->HandleKeyEvent(event); } + +void EditorFrame::OnMenuCustomizeAccelerators(wxCommandEvent& WXUNUSED(event)) { + (AcceleratorsDialog(this)).ShowModal(); +} \ No newline at end of file diff --git a/src/EditorFrame.h b/src/EditorFrame.h index fff33d39..e3503072 100644 --- a/src/EditorFrame.h +++ b/src/EditorFrame.h @@ -194,7 +194,8 @@ class EditorFrame : public KeyHookable, MENU_MACRO_FUNCTIONS, MENU_MACRO_REC, MENU_MACRO_PLAY, - MENU_MACRO_EDIT + MENU_MACRO_EDIT, + MENU_ACCELERATORS }; EditorFrame(CatalystWrapper cat, unsigned int frameId, const wxString& title, const wxRect& rect, TmSyntaxHandler& syntax_handler); @@ -495,6 +496,7 @@ class EditorFrame : public KeyHookable, void OnMenuMacroRec(wxCommandEvent& event); void OnMenuMacroPlay(wxCommandEvent& event); void OnMenuMacroEdit(wxCommandEvent& event); + void OnMenuCustomizeAccelerators(wxCommandEvent& event); void OnMenuKeyDiagnostics(wxCommandEvent& event); void OnTabsShowDropdown(wxCommandEvent& event); diff --git a/src/IEHtmlWin.cpp b/src/IEHtmlWin.cpp index c2d57b11..7fb858f2 100644 --- a/src/IEHtmlWin.cpp +++ b/src/IEHtmlWin.cpp @@ -250,7 +250,7 @@ class wxOwnedMemInputStream : public wxMemoryInputStream } }; -bool wxIEHtmlWin::LoadString(const wxString& html) +bool wxIEHtmlWin::LoadString(const wxString& html, bool prependHtml) { char *data = NULL; size_t len = html.length(); @@ -259,15 +259,15 @@ bool wxIEHtmlWin::LoadString(const wxString& html) #endif data = (char *) malloc(len); memcpy(data, html.c_str(), len); - return LoadStream(new wxOwnedMemInputStream(data, len)); + return LoadStream(new wxOwnedMemInputStream(data, len), prependHtml); }; -bool wxIEHtmlWin::LoadStream(IStreamAdaptorBase *pstrm) +bool wxIEHtmlWin::LoadStream(IStreamAdaptorBase *pstrm, bool prependHtml) { // need to prepend this as poxy MSHTML will not recognise a HTML comment // as starting a html document and treats it as plain text // Does nayone know how to force it to html mode ? - pstrm->prepend = ""; + if(prependHtml) pstrm->prepend = ""; // strip leading whitespace as it can confuse MSHTML wxAutoOleInterface strm(pstrm); @@ -296,22 +296,22 @@ bool wxIEHtmlWin::LoadStream(IStreamAdaptorBase *pstrm) return false; }; -bool wxIEHtmlWin::LoadStream(istream *is) +bool wxIEHtmlWin::LoadStream(istream *is, bool prependHtml) { // wrap reference around stream IStreamAdaptor *pstrm = new IStreamAdaptor(is); pstrm->AddRef(); - return LoadStream(pstrm); + return LoadStream(pstrm, prependHtml); }; -bool wxIEHtmlWin::LoadStream(wxInputStream *is) +bool wxIEHtmlWin::LoadStream(wxInputStream *is, bool prependHtml) { // wrap reference around stream IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is); pstrm->AddRef(); - return LoadStream(pstrm); + return LoadStream(pstrm, prependHtml); }; diff --git a/src/IEHtmlWin.h b/src/IEHtmlWin.h index 5df1d6b5..41c9deb8 100644 --- a/src/IEHtmlWin.h +++ b/src/IEHtmlWin.h @@ -46,9 +46,9 @@ class wxIEHtmlWin : public wxActiveX, public IHtmlWnd wxWindow* GetWindow(); void LoadUrl(const wxString &_url, const wxString &_frame = wxEmptyString, bool keepHistory=false); - bool LoadString(const wxString& html); - bool LoadStream(istream *strm); - bool LoadStream(wxInputStream *is); + bool LoadString(const wxString& html, bool prependHtml=true); + bool LoadStream(istream *strm, bool prependHtml=true); + bool LoadStream(wxInputStream *is, bool prependHtml=true); bool AppendString(const wxString& html); @@ -72,7 +72,7 @@ class wxIEHtmlWin : public wxActiveX, public IHtmlWnd void FreezeRedraw(bool on); protected: void SetupBrowser(); - bool LoadStream(IStreamAdaptorBase *pstrm); + bool LoadStream(IStreamAdaptorBase *pstrm, bool prependHtml=true); wxAutoOleInterface m_webBrowser; private: diff --git a/src/IHtmlWnd.h b/src/IHtmlWnd.h index 5366a35f..4f9437de 100644 --- a/src/IHtmlWnd.h +++ b/src/IHtmlWnd.h @@ -19,7 +19,7 @@ class IHtmlWnd { public: virtual ~IHtmlWnd() {}; virtual wxWindow* GetWindow() = 0; - virtual bool LoadString(const wxString& html) = 0; + virtual bool LoadString(const wxString& html, bool prependHtml=true) = 0; virtual void LoadUrl(const wxString &_url, const wxString &_frame = wxEmptyString, bool keepHistory=false) = 0; virtual bool Refresh(wxHtmlRefreshLevel level) = 0; virtual bool GoBack() = 0; diff --git a/src/e.vcproj b/src/e.vcproj index bdead61d..6ac5eb52 100644 --- a/src/e.vcproj +++ b/src/e.vcproj @@ -553,6 +553,18 @@ + + + + + +