add support for persistent controls

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58529 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2009-01-30 21:38:29 +00:00
parent b69470e4ee
commit 0fa541e870
25 changed files with 1548 additions and 20 deletions

222
include/wx/persist.h Normal file
View File

@@ -0,0 +1,222 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/persist.h
// Purpose: common classes for persistence support
// Author: Vadim Zeitlin
// Created: 2009-01-18
// RCS-ID: $Id: wxhead.h,v 1.10 2008-04-15 23:34:19 zeitlin Exp $
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PERSIST_H_
#define _WX_PERSIST_H_
#include "wx/string.h"
#include "wx/hashmap.h"
#include "wx/confbase.h"
class wxPersistentObject;
WX_DECLARE_VOIDPTR_HASH_MAP(wxPersistentObject *, wxPersistentObjectsMap);
// ----------------------------------------------------------------------------
// global functions
// ----------------------------------------------------------------------------
/*
We do _not_ declare this function as doing this would force us to specialize
it for the user classes deriving from the standard persistent classes.
However we do define overloads of wxCreatePersistentObject() for all the wx
classes which means that template wxPersistentObject::Restore() picks up the
right overload to use provided that the header defining the correct overload
is included before calling it. And a compilation error happens if this is
not done.
template <class T>
wxPersistentObject *wxCreatePersistentObject(T *obj);
*/
// ----------------------------------------------------------------------------
// wxPersistenceManager: global aspects of persistent windows
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxPersistenceManager
{
public:
// accessor to the unique persistence manager object
static wxPersistenceManager& Get();
// globally disable restoring or saving the persistent properties (both are
// enabled by default)
bool DisableSaving() { m_doSave = false; }
bool DisableRestoring() { m_doRestore = false; }
// register an object with the manager: when using the first overload,
// wxCreatePersistentObject() must be specialized for this object class;
// with the second one the persistent adapter is created by the caller
//
// the object shouldn't be already registered with us
template <class T>
wxPersistentObject *Register(T *obj)
{
return Register(obj, wxCreatePersistentObject(obj));
}
wxPersistentObject *Register(void *obj, wxPersistentObject *po);
// check if the object is registered and return the associated
// wxPersistentObject if it is or NULL otherwise
wxPersistentObject *Find(void *obj) const;
// unregister the object, this is called by wxPersistentObject itself so
// there is usually no need to do it explicitly
//
// deletes the associated wxPersistentObject
void Unregister(void *obj);
// save/restore the state of an object
//
// these methods do nothing if DisableSaving/Restoring() was called
//
// Restore() returns true if the object state was really restored
void Save(void *obj);
bool Restore(void *obj);
// combines both Save() and Unregister() calls
void SaveAndUnregister(void *obj)
{
Save(obj);
Unregister(obj);
}
// combines both Register() and Restore() calls
template <class T>
bool RegisterAndRestore(T *obj)
{
return Register(obj) && Restore(obj);
}
bool RegisterAndRestore(void *obj, wxPersistentObject *po)
{
return Register(obj, po) && Restore(obj);
}
// methods used by the persistent objects to save and restore the data
//
// currently these methods simply use wxConfig::Get()
//
// TODO: make this customizable by allowing
// (a) specifying custom wxConfig object to use
// (b) allowing to use something else entirely
template <typename T>
bool
SaveValue(const wxPersistentObject& who, const wxString& name, T value)
{
wxConfigBase * const conf = GetConfig();
if ( !conf )
return false;
return conf->Write(GetKey(who, name), value);
}
template <typename T>
bool
RestoreValue(const wxPersistentObject& who, const wxString& name, T *value)
{
wxConfigBase * const conf = GetConfig();
if ( !conf )
return false;
return conf->Read(GetKey(who, name), value);
}
private:
// ctor is private, use Get()
wxPersistenceManager()
{
m_doSave =
m_doRestore = true;
}
// helpers of Save/Restore(), will be customized later
wxConfigBase *GetConfig() const { return wxConfigBase::Get(); }
wxString GetKey(const wxPersistentObject& who, const wxString& name) const;
// map with the registered objects as keys and associated
// wxPersistentObjects as values
wxPersistentObjectsMap m_persistentObjects;
// true if we should restore/save the settings (it doesn't make much sense
// to use this class when both of them are false but setting one of them to
// false may make sense in some situations)
bool m_doSave,
m_doRestore;
DECLARE_NO_COPY_CLASS(wxPersistenceManager);
};
// ----------------------------------------------------------------------------
// wxPersistentObject: ABC for anything persistent
// ----------------------------------------------------------------------------
class wxPersistentObject
{
public:
// ctor associates us with the object whose options we save/restore
wxPersistentObject(void *obj) : m_obj(obj) { }
// trivial but virtual dtor
virtual ~wxPersistentObject() { }
// methods used by wxPersistenceManager
// ------------------------------------
// save/restore the corresponding objects settings
//
// these methods shouldn't be used directly as they don't respect the
// global wxPersistenceManager::DisableSaving/Restoring() settings, use
// wxPersistenceManager methods with the same name instead
virtual void Save() const = 0;
virtual bool Restore() = 0;
// get the kind of the objects we correspond to, e.g. "Frame"
virtual wxString GetKind() const = 0;
// get the name of the object we correspond to, e.g. "Main"
virtual wxString GetName() const = 0;
// return the associated object
void *GetObject() const { return m_obj; }
protected:
// wrappers for wxPersistenceManager methods which don't require passing
// "this" as the first parameter all the time
template <typename T>
bool SaveValue(const wxString& name, T value) const
{
return wxPersistenceManager::Get().SaveValue(*this, name, value);
}
template <typename T>
bool RestoreValue(const wxString& name, T *value)
{
return wxPersistenceManager::Get().RestoreValue(*this, name, value);
}
private:
void * const m_obj;
DECLARE_NO_COPY_CLASS(wxPersistentObject)
};
#endif // _WX_PERSIST_H_

View File

@@ -0,0 +1,67 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/persist/bookctrl.h
// Purpose: persistence support for wxBookCtrl
// Author: Vadim Zeitlin
// Created: 2009-01-19
// RCS-ID: $Id$
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PERSIST_BOOKCTRL_H_
#define _WX_PERSIST_BOOKCTRL_H_
#include "wx/persist/window.h"
#include "wx/bookctrl.h"
// ----------------------------------------------------------------------------
// string constants used by wxPersistentBookCtrl
// ----------------------------------------------------------------------------
#define wxPERSIST_BOOK_KIND "Book"
#define wxPERSIST_BOOK_SELECTION "Selection"
// ----------------------------------------------------------------------------
// wxPersistentBookCtrl: supports saving/restoring book control selection
// ----------------------------------------------------------------------------
class wxPersistentBookCtrl : public wxPersistentWindow<wxBookCtrlBase>
{
public:
wxPersistentBookCtrl(wxBookCtrlBase *book)
: wxPersistentWindow<wxBookCtrlBase>(book)
{
}
virtual void Save() const
{
SaveValue(wxPERSIST_BOOK_SELECTION, Get()->GetSelection());
}
virtual bool Restore()
{
long sel;
if ( RestoreValue(wxPERSIST_BOOK_SELECTION, &sel) )
{
wxBookCtrlBase * const book = Get();
if ( sel >= 0 && (unsigned)sel < book->GetPageCount() )
{
book->SetSelection(sel);
return true;
}
}
return false;
}
virtual wxString GetKind() const { return wxPERSIST_BOOK_KIND; }
};
inline wxPersistentObject *wxCreatePersistentObject(wxBookCtrlBase *book)
{
return new wxPersistentBookCtrl(book);
}
#endif // _WX_PERSIST_BOOKCTRL_H_

View File

@@ -0,0 +1,129 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/persist/toplevel.h
// Purpose: persistence support for wxTLW
// Author: Vadim Zeitlin
// Created: 2009-01-19
// RCS-ID: $Id$
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PERSIST_TOPLEVEL_H_
#define _WX_PERSIST_TOPLEVEL_H_
#include "wx/persist/window.h"
#include "wx/toplevel.h"
#include "wx/display.h"
// ----------------------------------------------------------------------------
// string constants used by wxPersistentTLW
// ----------------------------------------------------------------------------
// we use just "Window" to keep configuration files and such short, there
// should be no confusion with wxWindow itself as we don't have persistent
// windows, just persistent controls which have their own specific kind strings
#define wxPERSIST_TLW_KIND "Window"
// names for various persistent options
#define wxPERSIST_TLW_X "x"
#define wxPERSIST_TLW_Y "y"
#define wxPERSIST_TLW_W "w"
#define wxPERSIST_TLW_H "h"
#define wxPERSIST_TLW_MAXIMIZED "Maximized"
#define wxPERSIST_TLW_ICONIZED "Iconized"
// ----------------------------------------------------------------------------
// wxPersistentTLW: supports saving/restoring window position and size as well
// as maximized/iconized/restore state
// ----------------------------------------------------------------------------
class wxPersistentTLW : public wxPersistentWindow<wxTopLevelWindow>
{
public:
wxPersistentTLW(wxTopLevelWindow *tlw)
: wxPersistentWindow<wxTopLevelWindow>(tlw)
{
}
virtual void Save() const
{
const wxTopLevelWindow * const tlw = Get();
const wxPoint pos = tlw->GetScreenPosition();
SaveValue(wxPERSIST_TLW_X, pos.x);
SaveValue(wxPERSIST_TLW_Y, pos.y);
// notice that we use GetSize() here and not GetClientSize() because
// the latter doesn't return correct results for the minimized windows
// (at least not under Windows)
//
// of course, it shouldn't matter anyhow usually, the client size
// should be preserved as well unless the size of the decorations
// changed between the runs
const wxSize size = tlw->GetSize();
SaveValue(wxPERSIST_TLW_W, size.x);
SaveValue(wxPERSIST_TLW_H, size.y);
SaveValue(wxPERSIST_TLW_MAXIMIZED, tlw->IsMaximized());
SaveValue(wxPERSIST_TLW_ICONIZED, tlw->IsIconized());
}
virtual bool Restore()
{
wxTopLevelWindow * const tlw = Get();
long x wxDUMMY_INITIALIZE(-1),
y wxDUMMY_INITIALIZE(-1),
w wxDUMMY_INITIALIZE(-1),
h wxDUMMY_INITIALIZE(-1);
const bool hasPos = RestoreValue(wxPERSIST_TLW_X, &x) &&
RestoreValue(wxPERSIST_TLW_Y, &y);
const bool hasSize = RestoreValue(wxPERSIST_TLW_W, &w) &&
RestoreValue(wxPERSIST_TLW_H, &h);
if ( hasPos )
{
// to avoid making the window completely invisible if it had been
// shown on a monitor which was disconnected since the last run
// (this is pretty common for notebook with external displays)
//
// NB: we should allow window position to be (slightly) off screen,
// it's not uncommon to position the window so that its upper
// left corner has slightly negative coordinate
if ( wxDisplay::GetFromPoint(wxPoint(x, y)) != wxNOT_FOUND ||
(hasSize && wxDisplay::GetFromPoint(
wxPoint(x + w, y + h)) != wxNOT_FOUND) )
{
tlw->Move(x, y, wxSIZE_ALLOW_MINUS_ONE);
}
//else: should we try to adjust position/size somehow?
}
if ( hasSize )
tlw->SetSize(w, h);
// note that the window can be both maximized and iconized
bool maximized;
if ( RestoreValue(wxPERSIST_TLW_MAXIMIZED, &maximized) && maximized )
tlw->Maximize();
bool iconized;
if ( RestoreValue(wxPERSIST_TLW_ICONIZED, &iconized) && iconized )
tlw->Iconize();
// the most important property of the window that we restore is its
// size, so disregard the value of hasPos here
return hasSize;
}
virtual wxString GetKind() const { return wxPERSIST_TLW_KIND; }
};
inline wxPersistentObject *wxCreatePersistentObject(wxTopLevelWindow *tlw)
{
return new wxPersistentTLW(tlw);
}
#endif // _WX_PERSIST_TOPLEVEL_H_

View File

@@ -0,0 +1,97 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/persist/treebook.h
// Purpose: persistence support for wxBookCtrl
// Author: Vadim Zeitlin
// Created: 2009-01-19
// RCS-ID: $Id$
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PERSIST_TREEBOOK_H_
#define _WX_PERSIST_TREEBOOK_H_
#include "wx/persist/bookctrl.h"
#include "wx/arrstr.h"
#include "wx/treebook.h"
// ----------------------------------------------------------------------------
// string constants used by wxPersistentTreeBookCtrl
// ----------------------------------------------------------------------------
#define wxPERSIST_TREEBOOK_KIND "TreeBook"
// this key contains the indices of all expanded nodes in the tree book
// separated by wxPERSIST_TREEBOOK_EXPANDED_SEP
#define wxPERSIST_TREEBOOK_EXPANDED_BRANCHES "Expanded"
#define wxPERSIST_TREEBOOK_EXPANDED_SEP ','
// ----------------------------------------------------------------------------
// wxPersistentTreeBookCtrl: supports saving/restoring open tree branches
// ----------------------------------------------------------------------------
class wxPersistentTreeBookCtrl : public wxPersistentBookCtrl
{
public:
wxPersistentTreeBookCtrl(wxTreebook *book)
: wxPersistentBookCtrl(book)
{
}
virtual void Save() const
{
const wxTreebook * const book = GetTreeBook();
wxString expanded;
const size_t count = book->GetPageCount();
for ( size_t n = 0; n < count; n++ )
{
if ( book->IsNodeExpanded(n) )
{
if ( !expanded.empty() )
expanded += wxPERSIST_TREEBOOK_EXPANDED_SEP;
expanded += wxString::Format("%u", static_cast<unsigned>(n));
}
}
SaveValue(wxPERSIST_TREEBOOK_EXPANDED_BRANCHES, expanded);
wxPersistentBookCtrl::Save();
}
virtual bool Restore()
{
wxTreebook * const book = GetTreeBook();
wxString expanded;
if ( RestoreValue(wxPERSIST_TREEBOOK_EXPANDED_BRANCHES, &expanded) )
{
const wxArrayString
indices(wxSplit(expanded, wxPERSIST_TREEBOOK_EXPANDED_SEP));
const size_t pageCount = book->GetPageCount();
const size_t count = indices.size();
for ( size_t n = 0; n < count; n++ )
{
unsigned long idx;
if ( indices[n].ToULong(&idx) && idx < pageCount )
book->ExpandNode(idx);
}
}
return wxPersistentBookCtrl::Restore();
}
virtual wxString GetKind() const { return wxPERSIST_TREEBOOK_KIND; }
wxTreebook *GetTreeBook() const { return static_cast<wxTreebook *>(Get()); }
};
inline wxPersistentObject *wxCreatePersistentObject(wxTreebook *book)
{
return new wxPersistentTreeBookCtrl(book);
}
#endif // _WX_PERSIST_TREEBOOK_H_

View File

@@ -0,0 +1,85 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/persist/window.h
// Purpose: wxPersistentWindow declaration
// Author: Vadim Zeitlin
// Created: 2009-01-23
// RCS-ID: $Id$
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PERSIST_WINDOW_H_
#define _WX_PERSIST_WINDOW_H_
#include "wx/persist.h"
#include "wx/window.h"
// ----------------------------------------------------------------------------
// wxPersistentWindow: base class for persistent windows, uses the window name
// as persistent name by default and automatically reacts
// to the window destruction
// ----------------------------------------------------------------------------
// type-independent part of wxPersistentWindow
class wxPersistentWindowBase :
#if wxEVENTS_COMPATIBILITY_2_8
// in compatibility mode we need to derive from wxEvtHandler to be able to
// handle events
public wxEvtHandler ,
#endif
public wxPersistentObject
{
public:
wxPersistentWindowBase(wxWindow *win)
: wxPersistentObject(win)
{
win->Connect
(
wxEVT_DESTROY,
wxWindowDestroyEventHandler(
wxPersistentWindowBase::HandleDestroy),
NULL,
this
);
}
virtual wxString GetName() const
{
const wxString name = GetWindow()->GetName();
wxASSERT_MSG( !name.empty(), "persistent windows should be named!" );
return name;
}
protected:
wxWindow *GetWindow() const { return static_cast<wxWindow *>(GetObject()); }
private:
void HandleDestroy(wxWindowDestroyEvent& event)
{
event.Skip();
// this will delete this object itself
wxPersistenceManager::Get().SaveAndUnregister(GetWindow());
}
DECLARE_NO_COPY_CLASS(wxPersistentWindowBase)
};
template <class T>
class wxPersistentWindow : public wxPersistentWindowBase
{
public:
typedef T WindowType;
wxPersistentWindow(WindowType *win)
: wxPersistentWindowBase(win)
{
}
WindowType *Get() const { return static_cast<WindowType *>(GetWindow()); }
};
#endif // _WX_PERSIST_WINDOW_H_