%% options copyright owner = Dirk Krause copyright year = 2015-xxxx SPDX-License-Identifier: BSD-3-Clause %% header /** @file Dk4WxFrame.h Base class for top level frames. */ #ifndef DK4CONF_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4conf.h" #else #include #endif #endif #ifndef DK4TYPES_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4types.h" #else #include #endif #endif #ifndef WX_WXPREC_H_INCLUDED #include #define WX_WXPREC_H_INCLUDED 1 #endif #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #ifndef WX_WX_H_INCLUDED #include #define WX_WX_H_INCLUDED 1 #endif #endif #ifndef DK4WXAPPLICATIONHELPER_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "Dk4WxApplicationHelper.h" #else #include #endif #endif #ifndef DK4WXHELPCONTROLLER_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "Dk4WxHelpController.h" #else #include #endif #endif /** Frame (top level window). */ class Dk4WxFrame : public wxFrame { protected: /** Application helper. */ Dk4WxApplicationHelper *pAppHelp; /** Help controller for online help. */ Dk4WxHelpController *pHelp; /** Application name. */ wxString sAppName; /** Synchronize access to iInstances. */ static wxCriticalSection csInstances; /** Number of instances. */ static int iInstances; public: /** Constructor. @param appName Application name. @param appHelper Application helper. @param helpController Help controller. @param wxid Window ID. */ Dk4WxFrame( const wxString & appName, Dk4WxApplicationHelper *appHelper, Dk4WxHelpController *helpController, int wxid ); /** Restore previously saved window position. */ void RestorePosition(void); /** Handler for close event. @param event Event to process. */ void OnClose(wxCloseEvent & event); /** Decide whether we can close the frame. @param isFinal Flag: Final frame. @return True to close the frame, false to keep it. */ virtual bool CanClose(bool isFinal); /** Open help system. */ void DisplayContents(void); /** Open help section specified by name. @param name Section name. */ void DisplaySection(wxString const & name); /** Open a help section specified by number. @param number Section number (context ID). */ void DisplaySection(int number); /** Find data file and launch default application or web browser on it. @param fn File name to search for and use. @param bIsHelp Flag: File is a help file. @param bVerbose Flag: Show diagnostics on errors. @return Success indicator. */ bool FindFileAndLaunch( dkChar const *fn, bool bIsHelp = false, bool bVerbose = false ); protected: /** Save current window position. */ void SavePosition(void); }; %% module #ifndef DK4CONF_H_INCLUDED #include "dk4conf.h" #endif #ifndef DK4WXFRAME_H_INCLUDED #include "Dk4WxFrame.h" #endif #ifndef DK4MPL_H_INCLUDED #include "dk4mpl.h" #endif #ifndef DK4MEM_H_INCLUDED #include "dk4mem.h" #endif #ifndef DK4STRD_H_INCLUDED #include "dk4strd.h" #endif #ifndef DK4PATHD_H_INCLUDED #include "dk4pathd.h" #endif #ifndef DK4STRX_H_INCLUDED #include "dk4strx.h" #endif #ifndef DK4RECWX_H_INCLUDED #include "dk4recwx.h" #endif $!trace-include /** Protection for number of instances. */ wxCriticalSection Dk4WxFrame::csInstances; /** Number of instances. */ int Dk4WxFrame::iInstances = 0; /** Keywords to save and restore window size and position. */ static const wxChar * const dk4wxframe_kw_size[] = { $!string-table macro=wxT window.x window.y window.w window.h window.maximized window.iconized $!end }; /** Keywords to restore maximized and iconized state. */ static const wxChar * const dk4wxframe_kw_restore[] = { $!string-table macro=wxT window.restore-maximized window.restore-iconized window.restore-size $!end }; /** File name suffixes indicating to open file in web browser. */ static const wxChar * const dk4wxframe_suffix_web[] = { $!string-table macro=wxT .html .htm $!end }; /** Static text fragments, not localized. */ static const wxChar * const dk4wxframe_kwnl_wx[] = { $!string-table macro=wxT # # 0 URL suffix for local files. # file:// $!end }; Dk4WxFrame::Dk4WxFrame( const wxString & appName, Dk4WxApplicationHelper *appHelper, Dk4WxHelpController *helpController, int wxid ) : wxFrame(NULL, wxid, appName) { pAppHelp = appHelper; pHelp = helpController; sAppName = appName; { wxCriticalSectionLocker lock(csInstances); iInstances++; } Connect(wxid, wxEVT_CLOSE_WINDOW, wxCloseEventHandler(Dk4WxFrame::OnClose)); } void Dk4WxFrame::OnClose(wxCloseEvent & event) { bool doClose = true; bool isFinal = false; bool savePos = false; { wxCriticalSectionLocker lock(csInstances); if (1 == iInstances) { isFinal = true; } } if (event.CanVeto()) { doClose = CanClose(isFinal); } else { (void)CanClose(isFinal); } if (doClose) { { wxCriticalSectionLocker lock(csInstances); if (1 == iInstances--) { savePos = true; } } if (savePos) { SavePosition(); } event.Skip(); } else { event.Veto(); } } bool Dk4WxFrame::CanClose(bool WXUNUSED(isFinal)) { return true; } void Dk4WxFrame::SavePosition(void) { int iv[6]; $? "+ Dk4WxFrame::SavePosition" if (NULL != pAppHelp) { iv[4] = iv[5] = 0; if (IsIconized()) { iv[5] = 1; Iconize(false); } if (IsMaximized()) { iv[4] = 1; Maximize(false); } GetPosition(&(iv[0]), &(iv[1])); GetSize(&(iv[2]), &(iv[3])); $? ". saving current size" $? ". x = %d", iv[0] $? ". y = %d", iv[1] $? ". w = %d", iv[2] $? ". h = %d", iv[3] pAppHelp->SetMultiple(dk4wxframe_kw_size, iv, 6); } $? "- Dk4WxFrame::SavePosition" } void Dk4WxFrame::RestorePosition(void) { int iv[6]; /* Values stored in config */ bool bv[3]; /* Feature restore: maximized, iconized, position */ int x; /* X position */ int y; /* Y position */ int w; /* Width */ int h; /* Height */ $? "+ Dk4WxFrame::RestorePosition" /* Restore position by default. */ bv[2] = true; /* Initialize variables. */ iv[0] = iv[1] = -1; iv[2] = iv[3] = iv[4] = iv[5] = 0; bv[0] = bv[1] = false; /* Retrieve stored values if found. */ if (NULL != pAppHelp) { pAppHelp->GetMultiple(dk4wxframe_kw_size, iv, 6); $? ". iv[0] = %d", iv[0] $? ". iv[1] = %d", iv[1] $? ". iv[2] = %d", iv[2] $? ". iv[3] = %d", iv[3] $? ". iv[4] = %d", iv[4] $? ". iv[5] = %d", iv[5] pAppHelp->GetMultiple(dk4wxframe_kw_restore, bv, 3); $? ". bv[0] = %d", (bv[0] ? 1 : 0) $? ". bv[1] = %d", (bv[1] ? 1 : 0) $? ". bv[2] = %d", (bv[2] ? 1 : 0) } /* Find size if not stored. */ GetSize(&w, &h); x = iv[0]; y = iv[1]; $? ". x = %d", x $? ". y = %d", y $? ". w = %d", w $? ". h = %d", h /* Correct size if size restoration wanted, increase if necessary. */ if (bv[2]) { $? ". bv[2]" if (iv[2] > w) { w = iv[2]; $? ". w = %d", w } if (iv[3] > h) { h = iv[3]; $? ". h = %d", h } } /* Correct values, no parts of window should be outside screen. */ Dk4WxApplicationHelper::CorrectPosition(x, y, w, h); $? ". x = %d", x $? ". y = %d", y $? ". w = %d", w $? ". h = %d", h /* Set position and optionally size. */ if (bv[2]) { $? ". bv[2] active -> restore position and size" SetSize(x, y, w, h); #if wxCHECK_VERSION(3,0,0) { int t1 = 0; int t2 = 0; GetSize(&t1, &t2); if ((t1 > w) || (t2 > h)) { $? ". correction required" if (t1 > w) { w = w - (t1 - w); $? ". width correction required" } if (t2 > h) { h = h - (t2 - h); $? ". height correction required" } $? ". doing correction" SetSize(x, y, w, h); GetSize(&t1, &t2); $? ". width now %d", t1 $? ". height now %d", t2 } } #endif } else { $? ". bv[2] not active -> restore position only" SetPosition( wxPoint(x,y) ); } /* Restore maximized or iconized state if required. */ if (bv[0]) { $? ". bv[0] active -> maximize window" Maximize(0 != iv[4]); } #if TRACE_DEBUG else { $? ". bv[0] not active" } #endif if (bv[1]) { $? ". bv[1] active -> iconize" Iconize(0 != iv[5]); } #if TRACE_DEBUG else { $? ". bv[1] not active" } #endif $? "- Dk4WxFrame::RestorePosition" } void Dk4WxFrame::DisplayContents(void) { if (NULL != pHelp) { pHelp->DisplayContents(); } } void Dk4WxFrame::DisplaySection(wxString const & name) { if (NULL != pHelp) { pHelp->DisplaySection(name); } } void Dk4WxFrame::DisplaySection(int number) { if (NULL != pHelp) { pHelp->DisplaySection(number); } } bool Dk4WxFrame::FindFileAndLaunch(dkChar const *fn, bool bIsHelp, bool bVerbose) { wxChar bw[2 * DK4_MAX_PATH]; /* Full path in wxChar */ wxChar b2[2 * DK4_MAX_PATH]; dkChar b1[DK4_MAX_PATH]; /* Search result (full path) */ wxChar const *psuffix; /* File name suffix */ wxChar *pmod; size_t szb1 = DK4_SIZEOF(b1,dkChar); /* Size of b1 (num of dkChar) */ size_t szb2 = DK4_SIZEOF(b2,wxChar); /* Size of b2 (num of wxChar) */ size_t szbw = DK4_SIZEOF(bw,wxChar); /* Size of bw (num of wxChar) */ int res; /* Operation result */ int de; /* Destination encoding */ int se; /* Source encoding */ bool isweb; /* Use web browser */ bool done; /* Successfully done */ bool back; /* Result */ $? "+ FindFileAndLaunch \"%!ds\"", fn back = false; if ((NULL != fn) && (NULL != pAppHelp)) { done = false; /* Check for absolute path. Use absolute path unchanged. For a relative path do file search. */ if (0 != dk4path_is_absolute(fn)) { $? ". absolute path" if (0 != dk4str_cpy_s(b1, szb1, fn, NULL)) { $? ". found" done = true; } #if TRACE_DEBUG else { $? "! buffer too small" } #endif } else { $? ". relative path" if (bIsHelp) { if (pAppHelp->FindHelpFile(b1, szb1, fn)) { $? ". found" done = true; $? ". file name \"%!ds\"", b1 } #if TRACE_DEBUG else { $? "! not found" } #endif } else { if (pAppHelp->FindDataFile(b1, szb1, fn)) { $? ". found" done = true; $? ". file name \"%!ds\"", b1 } #if TRACE_DEBUG else { $? "! not found" } #endif } } if (done) { done = false; de = pAppHelp->GetWxEncoding(); se = pAppHelp->GetDkEncoding(); res = dk4recwx_dkchar_to_wxchar(bw, szbw, de, b1, se, NULL); if (0 != res) { $? ". recoding ok" isweb = false; $? ". file name \"%!ws\"", bw psuffix = dk4strx_get_path_suffix(bw, NULL); if (NULL != psuffix) { $? ". suffix found" if (0 <= dk4strx_array_index(dk4wxframe_suffix_web, psuffix, 0)) { isweb = true; $? ". is web" } } if (isweb) { $? ". is web" if (::wxLaunchDefaultBrowser(bw)) { done = true; $? ". launched (1)" back = true; } else { $? "! not launched (1)" if (0 != dk4strx_cpy_s(b2, szb2, dk4wxframe_kwnl_wx[0], NULL)) { $? ". url prefix" if (0 != dk4strx_cat_s(b2, szb2, bw, NULL)) { $? ". url constr" $? ". file name \"%!ws\"", b2 if (::wxLaunchDefaultBrowser(bw)) { $? ". launched (2)" done = true; back = true; } else { $? "! not launched (2)" pmod = &(b2[dk4strx_len(dk4wxframe_kwnl_wx[0])]); while (wxT('\0') != *pmod) { if (wxT('\\') == *pmod) { *pmod = wxT('/'); } pmod++; } $? ". url corrected \"%!ws\"", b2 $? ". file name \"%!ws\"", b2 if (::wxLaunchDefaultBrowser(bw)) { done = true; $? ". launched (3)" back = true; } #if TRACE_DEBUG else { $? "! no launched (3)" } #endif } } else { $? "! url construction" /* ##### ERROR: BUG */ } } else { $? "! url prefix" /* ##### ERROR: BUG */ } } } if (!(done)) { $? ". try application" #if wxCHECK_VERSION(3,0,0) if (::wxLaunchDefaultApplication(bw)) { $? ". launched (4)" done = true; back = true; } #if TRACE_DEBUG else { $? "! not launched (4)" } #endif #endif } if (!(done)) { /* ERROR: Failed to start application */ if (bVerbose) { wxString t; t.Append(pAppHelp->GetBasicString(12)); t.Append(bw); t.Append(pAppHelp->GetBasicString(13)); ::wxMessageBox( t, pAppHelp->GetBasicString(11), (wxOK | wxCENTRE | wxICON_ERROR) ); } } } else { $? "! recoding" /* ERROR: Recoding failed */ if (bVerbose) { ::wxMessageBox( pAppHelp->GetBasicString(10), pAppHelp->GetBasicString(9), (wxOK | wxCENTRE | wxICON_ERROR) ); } } } else { $? "! not found" /* ERROR: File not found */ if (bVerbose) { ::wxMessageBox( pAppHelp->GetBasicString(10), pAppHelp->GetBasicString(9), (wxOK | wxCENTRE | wxICON_ERROR) ); } } } #if TRACE_DEBUG else { $? "! args" } #endif $? "- FindFileAndLaunch" return back; }