//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1993, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of class TDocManager
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/docmanag.h>
#include <owl/appdict.h>
#include <owl/opensave.h>
#include <owl/picklist.h>
#include <owl/system.h>
#include <owl/filename.h>
#include <owl/docview.rh>
#include <string.h>
#include <stdio.h>
#include <dlgs.h>
#include <memory>
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
#endif
namespace owl {
//
// (Readable versions of) IDs of controls used by CommonDialogs
//
#define IDC_FILENAMETXT stc3
#define IDC_FILENAME edt1
#define IDC_FILELIST lst1
#define IDC_CURDIR stc1
#define IDC_DIRLIST lst2
#define IDC_FILETYPEEXT stc2
#define IDC_FILETYPES cmb1
#define IDC_DRIVESTEXT stc4
#define IDC_DRIVES cmb2
#define IDC_HELPF pshHelp
#define IDC_READONLY chx1
typedef TDocTemplate* TDocTemplatePtr;
OWL_DIAGINFO;
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlDocView, 1, 0);
//---------------------------------------------------------------------------
// class TDvOpenSaveData
//
//
/// Constructor of class representing the data to be displayed in the
/// Open/Save dialogs used by the DocManager.
//
TDvOpenSaveData::TDvOpenSaveData(uint32 flags, LPTSTR filter,
LPTSTR initialDir,
LPTSTR defExt,
int filterIndex, TDocTemplate **tmplList,
int tmplCount)
:
TOpenSaveDialog::TData(flags, filter, 0/*customFilter*/,
initialDir, defExt, 0/*maxPath*/, filterIndex),
TmplCount(tmplCount),
TmplList(tmplList)
{
}
//
/// Constructor of mixin. class used by the DocManager's version of the
/// Open/Save dialogs.
//
TDvOpenSaveDataOwner::TDvOpenSaveDataOwner(TDvOpenSaveData& data)
:
DvData(data)
{
}
//
/// 'HandleTemplateChanged' is invoked whenever the user switches the
/// file type in the FileOpen or FileSave dialog. The function updates
/// the internal OPENFILENAME structure based on the properties of the
/// new template selected.
//
static void
handleTemplateChanged(TDialog& dialog,
TDvOpenSaveDataOwner& dataOwner,
OPENFILENAME& ofn)
{
int index = static_cast<int>(dialog.SendDlgItemMessage(IDC_FILETYPES, CB_GETCURSEL));
if (index >= 0) {
CHECK(index < dataOwner.GetTmplCount());
TDocTemplate* tpl = dataOwner.GetTmplList()[index];
// Update default extension in OFN structure
//
CHECK(ofn.lpstrDefExt);
ofn.lpstrDefExt = tpl->GetDefaultExt();
}
}
//---------------------------------------------------------------------------
// class TDvFileOpenDialog
//
//
/// Constructor of object encapsulating the Open File dialog used by the
/// DocManager.
//
TDvFileOpenDialog::TDvFileOpenDialog(TWindow* parent, TDvOpenSaveData& data,
LPCTSTR title, TModule* module)
:
TFileOpenDialog(parent, data, 0/*templateId*/, title, module),
TDvOpenSaveDataOwner(data)
{
}
//
/// Overriden virtual function of TFileOpenDialog to allow us to detect when
/// the user switches between file types [i.e. DocView templates].
//
INT_PTR
TDvFileOpenDialog::DialogFunction(TMsgId message, TParam1 p1, TParam2 p2)
{
if (message == WM_COMMAND && LOWORD(p1) == IDC_FILETYPES &&
HIWORD(p1) == CBN_SELCHANGE) {
handleTemplateChanged(*this, *this, GetOFN());
}
return TFileOpenDialog::DialogFunction(message, p1, p2);
}
//---------------------------------------------------------------------------
// class TDvFileSaveDialog
//
//
/// Constructor of object encapsulating the FileSave dialog used by the
/// DocManager.
//
TDvFileSaveDialog::TDvFileSaveDialog(TWindow* parent, TDvOpenSaveData& data,
LPCTSTR title, TModule* module)
:
TFileSaveDialog(parent, data, 0/*templateId*/, title, module),
TDvOpenSaveDataOwner(data)
{
}
//
/// Overriden virtual function of TFileOpenDialog to allow us to detect when
/// the user switches between file types [i.e. DocView templates].
//
INT_PTR
TDvFileSaveDialog::DialogFunction(TMsgId message, TParam1 p1, TParam2 p2)
{
if (message == WM_COMMAND && LOWORD(p1) == IDC_FILETYPES &&
HIWORD(p1) == CBN_SELCHANGE) {
handleTemplateChanged(*this, *this, GetOFN());
}
return TFileSaveDialog::DialogFunction(message, p1, p2);
}
//----------------------------------------------------------------------------
// class TDocManager
//
DEFINE_RESPONSE_TABLE (TDocManager)
EV_WM_CANCLOSE,
EV_WM_PREPROCMENU,
EV_WM_WAKEUP,
EV_COMMAND(CM_FILENEW, CmFileNew),
EV_COMMAND(CM_FILEOPEN, CmFileOpen),
EV_COMMAND(CM_FILESAVE, CmFileSave),
EV_COMMAND(CM_FILESAVEAS, CmFileSaveAs),
EV_COMMAND(CM_FILEREVERT, CmFileRevert),
EV_COMMAND(CM_FILECLOSE, CmFileClose),
EV_COMMAND(CM_VIEWCREATE, CmViewCreate),
EV_COMMAND_ENABLE(CM_FILENEW, CeFileNew),
EV_COMMAND_ENABLE(CM_FILEOPEN, CeFileOpen),
EV_COMMAND_ENABLE(CM_FILESAVE, CeFileSave),
EV_COMMAND_ENABLE(CM_FILESAVEAS, CeFileSaveAs),
EV_COMMAND_ENABLE(CM_FILEREVERT, CeFileRevert),
EV_COMMAND_ENABLE(CM_FILECLOSE, CeFileClose),
EV_COMMAND_ENABLE(CM_VIEWCREATE, CeViewCreate),
END_RESPONSE_TABLE;
//
// Constructor of DocManager
//
/// The constructor performs the same operations as the first constructor. The
/// additional app parameter, however, points to the application associated with
/// this document.
//
TDocManager::TDocManager(int mode, TApplication* app, TDocTemplate*& templateHead)
{
Init(mode, app, templateHead);
}
//
/// Helper routine used by constructors.
///
/// Common initialization for TDocManager constructors (above constructor, &
/// compatable constructor below)
//
void
TDocManager::Init(int mode, TApplication* app, TDocTemplate*& templateHead)
{
Mode = mode;
TemplateList = templateHead;
TemplateHead = &templateHead;
UntitledIndex= 0;
AdditionalFileDialogFlags = 0;
PRECONDITION(app);
Application = app;
// Update docmanger pointer members of static templates
for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate())
tpl->DocManager = this;
}
//
/// Destruct this DocManager. Close all open documents (views close with them),
/// and delete all non-static doc templates
///
/// Destroys a TDocManager object removes attached documents templates. The
/// constructor resets TDocTemplate::DocTemplateStaticHead to point to the head of
/// the static template list.
//
TDocManager::~TDocManager()
{
// Iterate through document list, closing and deleting each
//
TDocument* doc;
while ((doc = DocList.Next(0)) != 0) {
if (doc->IsOpen())
doc->Close();
// NOTE: deleting the document deletes all attached views, and unlinks
// the document from the docmanager's document list
//
delete doc;
// Flush (dispatch) any pending MDI-Child-destroy messages
//
GetApplication()->PumpWaitingMessages();
}
// Reset the 'Docmanager' pointer of static templates and delete
// dynamic ones...
//
while (TemplateList) {
TDocTemplate* tpl = TemplateList;
TemplateList = tpl->GetNextTemplate();
if (tpl->IsStatic())
tpl->SetDocManager(0);
else
delete tpl;
}
}
//----------------------------------------------------------------------------
//
/// Count the number of templates, filtering by document type and/or view type as
/// indicated.
//
int
TDocManager::GetTemplateCount(TDocument* ofDocType, TView* ofViewType)
{
// No registered templates!!
//
if (!TemplateList) {
TRACEX(OwlDocView, 0, _T("GetTemplateCount(): No registered templates!"));
return 0;
}
// Walk through template list matching doc/view types as indicated
//
int tplCount = 0;
for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
if (ofDocType && !tpl->IsMyKindOfDoc(*ofDocType))
continue;
if (ofViewType && !tpl->IsMyKindOfView(*ofViewType))
continue;
tplCount++;
}
return tplCount;
}
//
/// Build a list of templates for creating new documents or opening existing
/// documents. Return the number of templates in the list. Passing 0 for tplList
/// skips the actual creation of the list, useful for pre-counting. size is only
/// used in the debug version.
//
#if __DEBUG < 2
int
TDocManager::GetNewTemplates(TDocTemplate** tplList, int, bool newDoc)
#else
int
TDocManager::GetNewTemplates(TDocTemplate** tplList, int size, bool newDoc)
#endif
{
// Check for no registered templates
//
if (!TemplateList) {
TRACEX(OwlDocView, 0, _T("GetNewTemplates(): No registered templates!"));
return 0;
}
// Walk thru all of the templates looking for visible ones, and if a new
// doc, non-dtReadOnly and non-dtForbidNew ones.
//
int tplCount = 0;
for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
if (tpl->IsVisible() &&
!((tpl->IsFlagSet(dtReadOnly) || tpl->IsFlagSet(dtForbidNew))
&& newDoc)){
if (tplList) {
CHECK(tplCount < size);
tplList[tplCount] = tpl;
}
tplCount++;
}
}
return tplCount;
}
//
/// Build a list of templates for saving documents. Return the number of templates
/// in the list. Passing 0 for tplList skips the actual creation of the list, useful
/// for pre-counting. size is only used in the debug version.
//
#if __DEBUG < 2
int
TDocManager::GetSaveTemplates(TDocTemplate** tplList, int,
TDocument& doc, bool sameDoc)
#else
int
TDocManager::GetSaveTemplates(TDocTemplate** tplList, int size,
TDocument& doc, bool sameDoc)
#endif
{
// Check for no registered templates
//
if (!TemplateList) {
TRACEX(OwlDocView, 0, _T("GetSaveTemplates(): No registered templates!"));
return 0;
}
// Walk thru all of the templates looking for visible, non-dtReadOnly ones,
// and if the same doc, ones that match the document
//
int tplCount = 0;
for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
if (tpl->IsVisible() && !tpl->IsFlagSet(dtReadOnly)
&& (!sameDoc || tpl->IsMyKindOfDoc(doc))) {
if (tplList) {
CHECK(tplCount < size);
tplList[tplCount] = tpl;
}
tplCount++;
}
}
return tplCount;
}
//
/// Build a list of templates for creating views. Return the number of templates in
/// the list. size is only used in the debug version.
///
/// \note To find out ahead of time how many templates match a particular document
/// type, use 'GetTemplateCount(docType);'
//
#if __DEBUG < 2
int
TDocManager::GetViewTemplates(TDocTemplate** tplList, int,
TDocument& doc)
#else
int
TDocManager::GetViewTemplates(TDocTemplate** tplList, int size,
TDocument& doc)
#endif
{
// Check for no registered templates
//
if (!TemplateList) {
TRACEX(OwlDocView, 0, _T("GetViewTemplates(): No registered templates!"));
return 0;
}
// Grab a list of templates for creating views
//
int tplCount = 0;
for (TDocTemplate* tpl = TemplateList; tpl; tpl = tpl->GetNextTemplate()) {
if (tpl->IsMyKindOfDoc(doc)) {
// Don't grab the same view more than once
//
LPCTSTR viewName = tpl->GetViewName();
int index;
for (index = 0; index < tplCount; index++) {
if (tplList[index]->GetViewName() == viewName)
break;
}
// Skip a view if the document already has one and the template
// specifies 'SingleView'.
//
if (tpl->IsFlagSet(dtSingleView)) {
TView* pview = 0;
while ((pview = doc.NextView(pview)) != 0)
if (tpl->IsMyKindOfView(*pview))
index = -1;
}
// Store the template if we have a match...
//
if (index == tplCount) {
CHECK(tplList);
CHECK(tplCount < size);
tplList[tplCount++] = tpl;
}
}
}
return tplCount;
}
//
/// Build up a long string containing the template descriptions and file filters for
/// every template in the given list. Return the length of the buffer needed.
/// Passing 0 for buffer skips actual buffer writing. size is only used in the debug
/// version. String will be in the form:
/// \code
/// "<descr1> (<filter1>)|(<filter1>)|<descr2> (<filter2>)|(<filter2>)|"
/// \endcode
//
#if __DEBUG < 2
int
TDocManager::GetTemplateDescription(TDocTemplate** tpllist, int tplcount,
LPTSTR buffer, int)
#else
int
TDocManager::GetTemplateDescription(TDocTemplate** tpllist, int tplcount,
LPTSTR buffer, int size)
#endif
{
int len = 0;
// If buffer is 0, then simply compute the length the template description(s)
// and filter(s)
//
if (!buffer) {
for (int count=0; count < tplcount; count++) {
TDocTemplate* tpl = tpllist[count];
CHECK(tpl);
LPCTSTR p = tpl->GetDescription();
int descLen = (p && *p) ? static_cast<int>(::_tcslen(p)) : 0;
p = tpl->GetFileFilter();
int fltrLen = (p && *p) ? static_cast<int>(::_tcslen(p)) : 0;
// Description + " (" + filter + ") " + filter +"|"
//
len += (descLen + 2 + fltrLen + 2 + fltrLen + 1);
}
}
else {
// Check that buffer is big enough
//
CHECK(GetTemplateDescription(tpllist, tplcount) < size);
// Put together a string of description and filters
//
buffer[0] = 0;
for (int count = 0; count < tplcount; count++ ) {
TDocTemplate* tpl = tpllist[count];
CHECK(tpl);
LPCTSTR p = tpl->GetDescription();
if (p && *p)
_tcscat(buffer, p);
p = tpl->GetFileFilter();
if (p && *p) {
_tcscat(buffer, _T(" ("));
_tcscat(buffer, p);
_tcscat(buffer, _T(")|"));
_tcscat(buffer, p);
}
_tcscat(buffer, _T("|"));
}
len = static_cast<int>(::_tcslen(buffer));
}
return len;
}
//----------------------------------------------------------------------------
//
/// Creates a document based on the directory path and the specified template. The
/// parameter flags, one of the document template constants, determines how the
/// document template is created. If path is 0 and this is not a new document (the
/// flag dtNewDoc is not set), it displays a dialog box. If path is 0 and dtNewDoc
/// is not set and more than one template exists, CreateAnyDoc displays a dialog box
/// and a list of templates.
//
TDocument*
TDocManager::CreateAnyDoc(LPCTSTR path, long flags)
{
// Are we creating a new document?
//
bool newDoc = (flags & dtNewDoc) ? true : false;
// Get a count and list of templates
//
int tplcount = GetNewTemplates(0, 0, newDoc);
// Return of there are no usable templates
//
if (!tplcount) {
TRACEX(OwlDocView, 0, _T("No usable templates found in CreateAnyDoc()"));
return 0;
}
// Allocate memory and get templates
//
TDocTemplatePtr* tpllist = new TDocTemplatePtr[tplcount];
TAPointer<TDocTemplatePtr> _clnObj(tpllist);
GetNewTemplates(tpllist, tplcount, newDoc);
tchar filepath[_MAX_PATH];
filepath[0] = 0;
// Find the index of the template to be used
//
int index;
if (newDoc) {
// If there's only one template, use it - otherwise prompt user
// to select the document type
//
if (tplcount == 1)
index = 1;
else
index = SelectDocType(tpllist, tplcount);
}
else {
// Select the doctemplate using the doc template filters
// !CQ might be nice to skip UI if path is already known, and maybe only
// !CQ if there is just one template
//
if (path)
::_tcscpy(filepath, path);
else
filepath[0] = 0;
index = SelectDocPath(tpllist, tplcount, filepath, COUNTOF(filepath), flags);
WARNX(OwlDocView, index > tplcount, 0,
_T("Invalid template index from SelectDocPath"));
}
// No index implies user cancelled or error
//
if (!index)
return 0;
// If opening a document, check that document is not already opened
//
if (filepath[0]) {
TDocument* doc = FindDocument(filepath);
if (doc != 0) {
PostDocError(*doc, IDS_DUPLICATEDOC);
return 0;
}
}
// We have a template, now create the document & return it if successful
//
return CreateDoc(tpllist[index-1], filepath, 0, flags);
}
//
/// CreateDoc creates a document based on the directory path and the specified
/// template. The flags parameter contains one of the document template constants
/// that determines how the document is created.
//
TDocument*
TDocManager::CreateDoc(TDocTemplate* tpl, LPCTSTR path,
TDocument* parent, long flags)
{
if (!tpl) {
TRACEX(OwlDocView, 0, _T("CreateDoc(): NULL template specified!"));
return 0;
}
// Creation step 0: Inform docmanager that we're about to create a document
// and allow docmanager to veto
//
if (!CreatingDoc(tpl)) {
TRACEX(OwlDocView, 1, _T("CreateDoc(): Creation vetoed."));
return 0;
}
// Creation step 1: Construct the document, passing in the parent document
// Put together a dummy parent document if no parent doc was specified in
// order to allow us to pass in the DocManager pointer hidden in the parent.
//
auto constructDoc = [&]
{
if (parent)
return tpl->ConstructDoc(parent);
else
{
TDocument dummy{this};
return tpl->ConstructDoc(&dummy);
}
};
auto d = std::unique_ptr<TDocument>{constructDoc()};
if (!d) {
TRACEX(OwlDocView, 0, _T("CreateDoc(): ConstructDoc call failed"));
return 0;
}
// Creation step2: Initialize the document
//
d->SetTemplate(tpl);
if (!InitDoc(d.get(), path, flags)) {
TRACEX(OwlDocView, 0, _T("CreateDoc: InitDoc failed"));
d.release(); // InitDoc failed and deleted the document.
return 0;
}
return d.release(); // Pass ownership to caller.
}
//
/// Initializes the document, using the given path for the document and the given document flags.
///
/// Prompts for pathname using TDocManager::SelectDocPath, if no path is supplied and not creating
/// a new document (i.e. the `dtNewDoc` flag is not set). If the user cancels the dialog, the
/// document is deleted and `nullptr` is returned.
///
/// \note Unless an exception is thrown, ownership of the given TDocument is taken on failure.
/// In particular, the document will be deleted if it cannot be properly initialized, if it cannot
/// be opened successfully (for `dtAutoOpen`), and unless `dtNoAutoView` is set, if creation of the
/// view fails. In these cases the function deletes the document and returns `nullptr`.
///
/// \sa See \ref docview_group for valid flags, such as `dtAutoDelete` and `dtNewDoc`.
//
TDocument*
TDocManager::InitDoc(TDocument* doc, LPCTSTR path, long flags)
{
PRECONDITION(doc);
TDocTemplate* tpl = doc->GetTemplate();
CHECKX(tpl, _T("TDocManager::InitDoc: No template"));
// Alter flags with template's flags
//
flags ^= tpl->GetFlags();
// Initialize new document
//
if (flags & dtNewDoc) {
doc->SetDocPath(0);
// Allow document to initialize and cleanup if unsuccessful
//
if (!doc->InitDoc()){
TRACEX(OwlDocView, 0, _T("TDocManager::InitDoc: Initialization failed"));
PostDocError(*doc, IDS_UNABLEOPEN);
delete doc;
return 0;
}
}
else {
if (!path) {
CHECKX(tpl->GetFileFilter(), _T("TDocManager::InitDoc: No file filter"));
// Prompt user for document's path
//
tchar filepath[_MAX_PATH];
filepath[0] = 0;
int index = SelectDocPath(&tpl, 1, filepath, COUNTOF(filepath), flags);
// if user cancelled UI, cleanup document
//
if (!index) {
TRACEX(OwlDocView, 0, _T("TDocManager::InitDoc: User cancellation"));
delete doc;
return 0;
}
path = filepath;
}
// Update document's path
//
doc->SetDocPath(path);
// Allow document to initialize and cleanup if unsuccessful
//
if (!doc->InitDoc()) {
TRACEX(OwlDocView, 0, _T("TDocManager::InitDoc: Initialization failed"));
PostDocError(*doc, IDS_UNABLEOPEN);
doc->SetDocPath(0); // fix by suggested Greg Chicares 06/04/98
delete doc;
return 0;
}
// Attempt to open document if 'dtAutoOpen' is enabled. Cleanup if
// unsuccessful.
//
if (flags & dtAutoOpen) {
if (!doc->Open((flags & dtNoReadOnly) ? ofReadWrite : ofRead, path)) {
TRACEX(OwlDocView, 0, _T("TDocManager::InitDoc: Cannot open the document"));
PostDocError(*doc, IDS_UNABLEOPEN);
doc->SetDocPath(0); // fix by suggested Greg Chicares 06/04/98
delete doc;
return 0;
}
}
}
// Create a view unless 'dtNoAutoView' flag is set. Cleanup on failure.
//
if (!(flags & dtNoAutoView)) {
if (!CreateView(*doc)) {
TRACEX(OwlDocView, 0, _T("TDocManager::InitDoc: Cannot create a view"));
if (doc->IsOpen())
doc->Close();
doc->SetDocPath(0);
delete doc;
return 0;
}
}
// Post event that document has been created
//
PostEvent(dnCreate, *doc); // WM_OWLDOCUMENT
return doc;
}
//
/// Creates a document view based on the directory path and specified template. The
/// parameter flags, one of the document template constants, determines how the
/// document template is created.
///
/// Create (Construct and Init) a view from registered templates supporting
/// a given doc.
///
/// This implementation allows user intervention if there is more than one
/// template available, by calling SelectViewType()
//
TView*
TDocManager::CreateAnyView(TDocument& doc, long /*flags*/)
{
int tplCount = GetTemplateCount(&doc);
// Abort if there are no usable templates
//
if (!tplCount) {
WARNX(OwlDocView, !tplCount, 0, _T("CreateAnyView(): no usable template"));
return 0;
}
// Allocate memory for templates and get 'em
//
TDocTemplatePtr* tplList = new TDocTemplatePtr[tplCount];
TAPointer<TDocTemplatePtr> _clnObj(tplList);
tplCount = GetViewTemplates(tplList, tplCount, doc);
int index;
if (tplCount > 1)
index = SelectViewType(tplList, tplCount);
else
index = tplCount;
if (index <= 0) {
WARNX(OwlDocView, !tplCount, 0, _T("CreateAnyView(): no usable template"));
WARNX(OwlDocView, tplCount, 0, _T("CreateAnyView(): invalid template index"));
return 0;
}
CHECK(index > 0);
//CHECK(index < tplCount);//?????????
CHECK(index <= tplCount);
// Now create the view on the document using the selected template
//
return CreateView(doc, tplList[index-1]);
}
//
/// Create a view on a given document using the given tempalte, or document's
/// template if none given, and then initialize the view. Return the view if
/// all was OK, or 0 if something failed.
//
TView*
TDocManager::CreateView(TDocument& doc, TDocTemplate* tpl)
{
// Default to the document's template if none provided
//
if (!tpl)
tpl = doc.GetTemplate();
CHECK(tpl);
TView* view = tpl->ConstructView(doc);
WARNX(OwlDocView, !view, 0, _T("CreateView(): ConstructView call failed"));
view = doc.InitView(view);
WARNX(OwlDocView, !view, 0, _T("CreateView(): InitView call failed"));
return view;
}
//----------------------------------------------------------------------------
//
/// Displays FileSave dialog prompting the user to select a file name for savinng the document.
/// Filters out read-only files.
//
bool
TDocManager::SelectSave(TDocument& doc)
{
TDocTemplate* tpl = doc.GetTemplate();
if (!tpl || !tpl->GetFileFilter())
return false;
tchar filepath[_MAX_PATH];
if (doc.GetDocPath())
::_tcscpy(filepath, doc.GetDocPath());
else
filepath[0] = 0; // no initial file path
int index = SelectDocPath(&tpl, 1, filepath, COUNTOF(filepath), 0, true, &doc);
return index ? doc.SetDocPath(filepath) : false;
}
//
/// Select a new docpath for a document from the registered templates
/// supporting the doc.
//
TDocTemplate*
TDocManager::SelectAnySave(TDocument& doc, bool samedoc)
{
int tplcount = GetSaveTemplates(0, 0, doc, samedoc);
// Abort if there are no usable templates
//
if (!tplcount) {
WARNX(OwlDocView, !tplcount, 0, _T("SelectAnySave(): no usable templates"));
return 0;
}
// Allocate memory for templates and get 'em
//
TDocTemplatePtr* tpllist = new TDocTemplatePtr[tplcount];
TAPointer<TDocTemplatePtr> _clnObj(tpllist);
GetSaveTemplates(tpllist, tplcount, doc, samedoc);
// Grab the file name, if there's one
//
tchar filepath[_MAX_PATH];
if (doc.GetDocPath())
::_tcscpy(filepath, doc.GetDocPath());
else
filepath[0] = 0;
// Allow UI for user input
//
int index;
index = SelectDocPath(tpllist, tplcount, filepath, COUNTOF(filepath), 0, true, &doc);
if (!index)
return 0;
CHECK(index >= 1);
CHECK(index <= tplcount);
// Perform save by setting the new path into the doc
// !CQ Also notify doc of save somehow?
//
if (!doc.SetDocPath(filepath))
return 0;
return tpllist[index-1];
}
//
/// Method invoked when specified document is about to be closed.
/// Updates the document with any changes and prompts the user for confirmation of
/// updates.
/// Returns 'true' if DocManager should proceed with the closing
/// stages of the document, or 'false' otherwise.
//
bool
TDocManager::FlushDoc(TDocument& doc)
{
while (doc.IsDirty()) {
int saveOrNot = doc.IsEmbedded() ?
IDYES :
PostDocError(doc, IDS_DOCCHANGED, MB_YESNOCANCEL);
switch (saveOrNot) {
case IDYES:
// Prompt the user for filename in save-as situation
//
if (!doc.IsEmbedded() && doc.GetDocPath() == 0) {
// !BB
// !BB It does not make sense to invoke SelectAnySave
// !BB with false here... This would allow the user
// !BB to switch to any available template when saving the
// !BB document. In other words, a user would be allowed to
// !BB save a .TXT file as a .PTS file although they are
// !BB not related whatsoever...
// !BB
// !BB I'm switching this to use true - let me know if you
// !BB know of a reason for the prior behaviour.
// !BB
#if defined(OLD_DOCVIEW)
TDocTemplate* tpl = SelectAnySave(doc, false);
#else
TDocTemplate* tpl = SelectAnySave(doc, true);
#endif
if (!tpl)
continue;
// !BB
// !BB The following is suspicious: Is there a reason
// !BB to allow the user to switch the template in the first
// !BB place?? OK, if everyone agrees that same TDocument-derived
// !BB type implies compatible document, that would be OK.
// !BB However, that's not what we've encouraged. Our own
// !BB examples use the same TFileDocument for incompatible
// !BB document types. Hence, if an app. has a
// !BB TBitmapView/TFileDocument and a TTextView/TFileDocument pair,
// !BB the following would allow the user to save a text file as a .BMP
// !BB Ack!!
// !BB If the following is really the intent, then DV users must be
// !BB conscious that they will more often than not be using TFileDocument-
// !BB derived documents as a method to specify compatible and incompatible
// !BB document types.
//
if (tpl != doc.Template)
doc.SetTemplate(tpl);
}
if (doc.Commit())
return true;
continue;
case IDNO:
if (doc.Revert(true))
return true;
return false;
case IDCANCEL:
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
//
/// Returns the first registered template whose pattern matches the given file name.
/// If no template is compatible with the supplied file name, or if the template is
/// open already, it returns 0.
///
/// This implementation compares the path's extension with the ';' separated
/// filter lists in each template looking for a case-insensitive match. Allows
/// '?'s in the template filters to match any character in the path's extension
///
/// Example:
///
/// The path: "documents.1995\accounts_receivable.plan"
///
/// Would match the filter: "*.xls;*.wk?;*.plan"
//
TDocTemplate*
TDocManager::MatchTemplate(LPCTSTR path)
{
// !BB if (FindDocument(path))
// !BB return 0;
// Iterate through templates
//
for (TDocTemplate* tpl = TemplateList; tpl != 0; tpl = tpl->GetNextTemplate()) {
// Skip hidden templates or templates without filters specified
//
LPCTSTR tplFilter = tpl->GetFileFilter();
if (!tplFilter || tpl->IsFlagSet(dtHidden))
continue;
if (TDocManager::MatchFilter(path, tplFilter))
return tpl;
}
return 0;
}
//
/// Helper function used by 'MatchTemplate'. Returns true if the specified file name
/// (path) matches any of the patterns of the 'filters' parameter. Returns false otherwise.
//
bool
TDocManager::MatchFilter(LPCTSTR path, LPCTSTR filters)
{
// Make locale copy of filter
//
TAPointer<tchar> fltrCopy(nstrnewdup(filters));
LPTSTR fltr = fltrCopy;
LPTSTR nxtFltr;
// For each template, try each wilcard specified
//
while (fltr) {
// Is there another wildcard following - Null terminate at ';'
//
nxtFltr = _tcschr(fltr, _T(';'));
if (nxtFltr)
*nxtFltr++ = 0;
if (IsAMatch(path, fltr))
return true;
// Try next filter
//
fltr = (nxtFltr && *nxtFltr) ? nxtFltr : 0;
}
return false;
}
//
/// Internal routine used to match a portion of a filename (i.e. name or
/// extension) to a wilcard pattern.
//
static bool
nameMatch(LPCTSTR name, LPCTSTR wc)
{
while (true) {
//if (*wc == _T('*') || (!*wc && !*name))
// Greg Bullock suggestion
if ((*wc == _T('*') && (wc[1] == _T('\0'))) || (!*wc && !*name))
return true;
if (*wc == _T('*')) {
// The wildcard string begins with '*' but ends with something else (e.g., "*~")
// We'll need to verify that the ending of name matches the wildcard string.
wc++;
size_t namelen = _tcslen(name);
size_t wclen = _tcslen(wc);
if (namelen > wclen)
name += namelen - wclen;
}
#if defined(BI_DBCS_SUPPORT)
int n = CharSize(name);
if (*wc == _T('?') && *name) {
wc++;
name += n;
continue;
}
else if (n > 1) { // if double byte character
if (_tcsncmp(name, wc, n) == 0) {
wc += n;
name += n;
continue;
}
}
else if (_totupper(*name) == _totupper(*wc)) {
#else
if ((*wc == _T('?') && *name) || (_totupper(*name) == _totupper(*wc))) {
#endif
wc++;
name++;
continue;
}
break;
}
return false;
}
//
/// Helper function used by 'MatchTemplate'. Returns true if the specified file name
/// (path) matches the pattern of the 'filter' parameter. Returns false otherwise.
//
bool
TDocManager::IsAMatch(LPCTSTR path, LPCTSTR fltr)
{
PRECONDITION(path);
PRECONDITION(fltr);
// Ensure path has at least a valid file name
//
TFileName fname(path);
if (!fname.HasParts(TFileName::File)) {
TRACEX(OwlDocView, 0, _T("IsAMatch: Invoked with invalid path"));
return false;
}
// Retrieve name/extension from path
//
tstring name = fname.GetParts(TFileName::File);
tstring ext = fname.GetParts(TFileName::Ext);
// Get pointers to path's name and extension
//
LPCTSTR ppn = name.c_str();
LPCTSTR ppe = fname.HasParts(TFileName::Ext) ? ext.c_str() : _T("");
if (*ppe == _T('.'))
ppe++;
// Get pointers to filter's name and extension
//
TAPointer<tchar> filter(nstrnewdup(fltr));
tchar* pfn = filter;
tchar* pfe = _tcsrchr(filter, _T('.'));
// Skip past '.' separator of filter
//
if (pfe)
*pfe++ = 0;
const tchar* const cpfe = pfe ? pfe : _T("");
// Match the name and extension
//
return nameMatch(ppn, pfn) && nameMatch(ppe, cpfe);
}
//
/// Calls TWindow::GetFocus() to determine the window with the focus. Searches the
/// list of documents and returns the document that contains the view with the
/// focus. Returns 0 if no document has a view with focus.
//
TDocument*
TDocManager::GetCurrentDoc()
{
PRECONDITION(GetApplication());
PRECONDITION(GetApplication()->GetMainWindow());
HWND hWnd = GetApplication()->GetMainWindow()->GetCommandTarget();
TDocument* doc = 0;
#if defined(OLD_DOCVIEW)
// !BB This older implementation of GetCurrentDoc relies on the
// !BB document's HasFocus method which does not allow 'GetCurrentDoc'
// !BB to return child documents....
// !BB
// !BB This obviously causes some problems (for example, closing a view
// !BB associated with a child document closes the whole document and
// !BB all their associated views!).
// !BB
// !BB However is there code that relies on this behaviour - Investigate
// !BB
if (hWnd && ::IsWindow(hWnd)) {
while ((doc = DocList.Next(doc)) != 0 && !doc->HasFocus(hWnd))
;
}
#else
if (hWnd && ::IsWindow(hWnd)) {
while ((doc = DocList.Next(doc)) != 0 ) {
TDocument* childDoc = doc->DocWithFocus(hWnd);
if (childDoc) {
doc = childDoc;
break;
}
}
}
#endif
return doc;
}
//
/// Returns a pointer to the TDocument object if the specified document
/// is currently opened and manager by the DocManager. Returns 0 otherwise.
//
TDocument*
TDocManager::FindDocument(LPCTSTR path)
{
TDocument* doc = 0;
while ((doc = DocList.Next(doc)) != 0)
if (path) {
if (doc->GetDocPath() && _tcsicmp(doc->GetDocPath(), path) == 0)
break;
}
else {
if (doc->GetDocPath() == 0)
break;
}
return doc;
}
//----------------------------------------------------------------------------
//
/// Adds a template to the template list managed by the DocManager.
//
void
TDocManager::AttachTemplate(TDocTemplate& tpl)
{
tpl.SetDocManager(this);
TDocTemplate::AddLink((TRegLink**)&TemplateList, &tpl);
}
//
/// Removes a template from the list of templates currently managed by
/// the DocManager.
//
void
TDocManager::DeleteTemplate(TDocTemplate& tpl)
{
// Skip static templates
//
if (tpl.IsStatic()) {
TRACEX(OwlDocView, 0, _T("TDocManager::DeleteTemplate() invoked for static"));
return;
}
// Check if it has an owner
//
if (!tpl.GetDocManager()) {
TRACEX(OwlDocView, 0, _T("TDocManager::DeleteTemplate(), templ. has no owner"));
return;
}
// Unreference the template - will be deleted unless documents
// still reference template.
//
if (TDocTemplate::RemoveLink((TRegLink**)&TemplateList, &tpl)) {
UnRefTemplate(tpl);
return;
}
TRACEX(OwlDocView, 0, _T("TDocManager::DeleteTemplate(), not in app list"));
}
//----------------------------------------------------------------------------
//
/// Displays a message box with the error message passed as a string resource ID in
/// sid. By default, the message box contains either an OK push button or a question
/// mark icon. If an error message can't be found, PostDocError displays a "Message
/// not found" message. choice can be one or more of the MB_Xxxx message style
/// constants. This function can be overridden.
///
/// Returns an integer
/// identifying the MessageBox option (push-button) selected by the user.
//
uint
TDocManager::PostDocError(TDocument& doc, uint sid, uint choice)
{
PRECONDITION(GetApplication());
PRECONDITION(GetApplication()->GetMainWindow());
tchar buf[256];
if (GetApplication()->LoadString(sid, buf, sizeof(buf) / sizeof(tchar)) == 0)
#if BI_MSG_LANGUAGE == 0x0411
_stprintf(buf, "�װ: ������ ID %u ��������܂���", sid);
#else
_stprintf(buf, _T("Error: Message [string ID %u] not found"), sid);
#endif
if (choice != MB_OK)
choice |= MB_ICONQUESTION;
return GetApplication()->GetMainWindow()->MessageBox(buf, doc.GetTitle(), choice);
}
//
/// Post a OWL-defined message regarding an event [identified by the 'id'
/// parameter] related to the specified document ('doc').
//
/// If the current document changes, posts a WM_OWLDOCUMENT message to indicate a
/// change in the status of the document.
//
void
TDocManager::PostEvent(int id, TDocument& doc)
{
TWindow* win = GetApplication()->GetMainWindow();
if (win && win->GetHandle())
win->SendMessage(WM_OWLDOCUMENT, id, TParam2(&doc));
}
//
/// Post a OWL-defined message regarding an event [identified by the 'id'
/// parameter] related to the specified view ('view').
//
/// If the current view changes, posts a WM_OWLVIEW message to indicate a change in
/// the status of the view.
//
void
TDocManager::PostEvent(int id, TView& view)
{
TWindow* win = GetApplication()->GetMainWindow();
if (win && win->GetHandle())
win->SendMessage(WM_OWLVIEW, id, TParam2(&view));
}
//----------------------------------------------------------------------------
//
/// Given a list of templates, lets the user select a document type from a list of document templates. Returns
/// the template index used for the selection, or 0 if unsuccessful. SelectDocType
/// can be overridden.
//
int
TDocManager::SelectDocType(TDocTemplate** tpllist, int tplcount)
{
TPickListPopup pickl(GetApplication()->GetMainWindow(), IDS_DOCLIST);
while (tplcount--) {
CHECK(*tpllist);
pickl.AddString((*tpllist++)->GetDescription());
}
int index = pickl.Execute() + 1;
if (index == -1)
return 0;
return index;
///TH This does not look right, crashes when user cancels twice
// return pickl.Execute() + 1;
}
//
/// Given a list of templates, prompts the user to select one of the templates to use for the file to be
/// opened. Returns the template index used for the selection, or 0 if unsuccessful.
/// For a file open operation, save is false. For a file save operation, save is
/// true. This function can be overridden to provide a customized user interface.
///
/// \note This is Windows-specific, using the system-provided file open dialog box
//
int
TDocManager::SelectDocPath(TDocTemplate** tpllist, int tplcount,
LPTSTR path, int buflen, long flags,
bool save, TDocument* doc)
{
// Compute length of description(s) and filter(s)
//
int len = GetTemplateDescription(tpllist, tplcount);
// Put together a string of description and filters
//
TAPointer<tchar> filtbuf(new tchar[++len]);
GetTemplateDescription(tpllist, tplcount, filtbuf, len);
// Find the (default) template to select
//
int index, count;
TDocument* curDoc = save ? (doc ? doc : GetCurrentDoc()) : 0;
CHECK(!save || curDoc);
if (save) {
for (index = count = 0; count < tplcount; count++) {
if (tpllist[count] == curDoc->GetTemplate()) {
index = count;
break;
}
}
}
else {
for (index = count = 0; count < tplcount; count++) {
if (tpllist[count]->IsFlagSet(dtSelected)) {
index = count;
break;
}
}
}
// Initialize data structure used for launching Common Dialog
//
flags = (tpllist[index]->GetFlags() | flags);
flags &= 0x000FFFFF; // Clear Doc/View related flags.
flags |= AdditionalFileDialogFlags; // Add extended flags, e.g. OFN_ENABLESIZING.
flags &= ~dtProhibited; // Clear unsupported flags, e.g. OFN_ENABLETEMPLATE.
TDvOpenSaveData data(flags, // flags
filtbuf, // filter
CONST_CAST(LPTSTR, tpllist[index]->GetDirectory()), // initDir.
CONST_CAST(LPTSTR, tpllist[index]->GetDefaultExt()), // defExt.
index ? index+1 : 0, // filterIndex
tpllist, // template list
tplcount); // template count
//--- Sirma (Krasi)
{
LPCTSTR fName = path && *path ? path : (doc ? doc->GetTitle() : 0);
if (fName && *fName)
_tcsncpy(data.FileName, fName, buflen);
}
//--- Sirma (Krasi) ---
// Execute dialog
//
int result;
TWindow* parent = GetApplication()->GetMainWindow();
if (save)
result = TDvFileSaveDialog(parent, data).Execute();
else
result = TDvFileOpenDialog(parent, data).Execute();
WARNX(OwlDocView, data.Error != 0, 0, _T("Common dialog error: ") << data.Error << _T(" in SelectDocPath()"));
if (result != IDOK || data.Error != 0) return 0; // Dialog was cancelled or failed.
// !BB
// Here, there's a major dilemma! How, do we know the user did not
// mislead us? For example, the user may have selected the *wrong*
// template for saving a particular document... This is crucial when
// saving documents!!!
//
// Update templates to 'remember' the template last used
//
for (count = 0; count < tplcount; count++) {
if (count == index-1)
tpllist[count]->SetFlag(dtSelected);
else
tpllist[count]->ClearFlag(dtSelected);
}
// Update selected template with directory
//
// // !BB Yeah! Where's the meat?
// Copy file name over
//
CHECK(path);
if (data.FileName && data.FileName[0]) {
WARNX(OwlDocView, ::_tcslen(data.FileName) < (size_t)buflen, 0,
_T("SelectDocPath: Specified buffer is too small"));
_tcsncpy(path, data.FileName, buflen);
}
else
*path = 0;
// Return index [1-based] of selected template
//
CHECK(data.FilterIndex >= 1);
CHECK(data.FilterIndex <= tplcount);
return data.FilterIndex;
}
//
/// Given a list of templates, lets the user select a view name for a new view from a list of view names.
/// Returns the template index used for the selection or 0 if unsuccessful.
/// SelectViewType can be overridden,
//
int
TDocManager::SelectViewType(TDocTemplate** tpllist, int tplcount)
{
TPickListPopup pickl(GetApplication()->GetMainWindow(), IDS_VIEWLIST);
while (tplcount--) {
CHECK(*tpllist);
pickl.AddString((*tpllist++)->GetViewName());
}
return pickl.Execute() + 1;
}
//
/// Overrideable method invoked just before the DocumentManager creates a new
/// document. The default behaviour is to close and delete the current
/// document if we're in SDI mode.
//
bool
TDocManager::CreatingDoc(TDocTemplate* /*tpl*/)
{
if (Mode & dmSDI) {
TDocument* doc = DocList.Next(0);
if (doc) {
if (!doc->CanClose())
return false;
if (!doc->Close()) {
PostDocError(*doc, IDS_UNABLECLOSE);
return false;
}
delete doc;
}
}
return true;
}
//
/// Update the specified menu bar by removing the current '&File' popup menu [assumed
/// to be the first popup of the menubar] and replacing it with the ObjectWindows'
/// standard File popup menu resource.
//
void
TDocManager::UpdateFileMenu(TMenu& menubar)
{
PRECONDITION(GetApplication());
HMENU hMenu = GetApplication()->LoadMenu(IDM_DOCMANAGERFILE);
if (!hMenu)
hMenu = GetGlobalModule().LoadMenu(IDM_DOCMANAGERFILE);
if (hMenu) {
tchar menuTitle[40];
GetApplication()->LoadString(IDS_DOCMANAGERFILE, menuTitle, sizeof(menuTitle) / sizeof(tchar));
TMenu filePopup(hMenu);
if (Mode & dmNoRevert)
filePopup.DeleteMenu(CM_FILEREVERT, MF_BYCOMMAND);
// Assumes '&File' popup is first entry of menubar...
//
menubar.DeleteMenu(0, MF_BYPOSITION);
menubar.InsertMenu(0, MF_BYPOSITION|MF_POPUP, reinterpret_cast<TMenuItem>(hMenu), menuTitle);
}
WARNX(OwlDocView, !hMenu, 0, _T("Cannot load DocManager's File Menu"));
}
//
/// Notifies the views of all documents and the views of any child documents
/// of a change. Returns true if all views returned a true result.
//
bool TDocManager::NotifyAllDocs(int event, long item, TView* exclude)
{
bool answer = true;
TDocument* doc = 0;
while ((doc = DocList.Next(doc)) != 0)
{
bool r = doc->NotifyViews(event, item, exclude);
answer = answer && r;
}
return answer;
}
//----------------------------------------------------------------------------
//
/// Checks to see if all child documents can be closed before closing the current
/// document. If any child returns false, returns false and aborts the process. If
/// all children return true, EvCanClose calls TDocManager::FlushDoc for each
/// document. If FlushDoc finds that the document is dirty, it displays a message
/// asking the user to save the document, discard any changes, or cancel the
/// operation. If the document is not dirty and CanClose returns true, EvCanClose
/// returns true.
//
bool
TDocManager::EvCanClose()
{
TDocument* doc = 0;
while ((doc = DocList.Next(doc)) != 0) {
if (!doc->CanClose()) // normally calls back to FlushDoc()
return false;
}
return true;
}
//
/// Preprocess the app frame's menu to replace the file menu with one managed
/// by this docmanager
//
/// Called from MainWindow, EvPreProcessMenu loads and deletes a menu at the
/// position specified by MF_POSITION or MF_POPUP. Your application can call
/// EvPreProcessMenu to process the main window's menu before it is displayed.
//
void
TDocManager::EvPreProcessMenu(HMENU hMenuBar)
{
if (Mode & dmMenu){
TMenu menu(hMenuBar);
UpdateFileMenu(menu);
}
}
//
/// Used only after streaming in the doc manager, EvWakeUp allows for the windows to
/// be created after the streaming has occurred.
//
void
TDocManager::EvWakeUp()
{
TDocument* doc = 0;
while ((doc = DocList.Next(doc)) != 0)
doc->ReindexFrames();
}
//----------------------------------------------------------------------------
// Command event handlers
//
//
/// Command enabler for CmFileNew.
//
void
TDocManager::CeFileNew(TCommandEnabler& ce)
{
ce.Enable(TemplateList != 0);
}
//
//
//
void
TDocManager::FileNew()
{
CreateAnyDoc(0, dtNewDoc);
}
//
/// Command enabler for CmFileOpen.
//
void
TDocManager::CeFileOpen(TCommandEnabler& ce)
{
ce.Enable(TemplateList != 0);
}
//
//
//
void
TDocManager::FileOpen()
{
CreateAnyDoc(0, 0);
}
//
/// Command enabler for CmFileClose.
//
void
TDocManager::CeFileClose(TCommandEnabler& ce)
{
ce.Enable(GetCurrentDoc() != 0);
}
//
/// If the document can be closed it is closed.
//
void
TDocManager::FileClose()
{
TDocument* doc = GetCurrentDoc();
if (doc && doc->CanClose()) { // normally calls back to FlushDoc()
if (!doc->Close())
PostDocError(*doc, IDS_UNABLECLOSE);
else
delete doc;
}
WARNX(OwlDocView, !doc, 0, _T("FileClose invoked with no current doc"));
}
//
/// Command enabler for CmFileSaveAs.
//
void
TDocManager::CeFileSaveAs(TCommandEnabler& ce)
{
TDocument* doc = GetCurrentDoc();
ce.Enable(doc != 0);
}
//
/// SelectAnySave() is called to get a template. Then the Commit() function is called
/// for the current document.
//
void
TDocManager::FileSaveAs()
{
TDocument* doc = GetCurrentDoc();
if (doc) {
TDocTemplate* tpl = SelectAnySave(*doc, true);
if (tpl) {
if (tpl != doc->Template)
doc->SetTemplate(tpl); // replace existing template
if (doc->Commit(true)) // force rewrite to new path
PostEvent(dnRename, *doc); // WM_OWLDOCUMENT
}
}
}
//
/// Command enabler for CmFileSave.
//
void
TDocManager::CeFileSave(TCommandEnabler& ce)
{
TDocument* doc = GetCurrentDoc();
ce.Enable(doc && (doc->IsDirty() || (Mode & dmSaveEnable)));
}
//
//
//
void
TDocManager::FileSave()
{
TDocument* doc = GetCurrentDoc();
if (doc) {
if (!doc->GetDocPath()) {
CmFileSaveAs();
return;
}
if (!(Mode & dmSaveEnable) && !doc->IsDirty()) {
PostDocError(*doc, IDS_NOTCHANGED);
return;
}
doc->Commit(); // No force of write here since is just to same file
}
}
//
/// Command enabler for CmFileRevert.
//
void
TDocManager::CeFileRevert(TCommandEnabler& ce)
{
TDocument* doc = GetCurrentDoc();
ce.Enable(doc && doc->IsDirty() && doc->GetDocPath());
}
//
//
//
void
TDocManager::FileRevert()
{
TDocument* doc = GetCurrentDoc();
if (doc && doc->GetDocPath()) {
if (!doc->IsDirty()) {
PostDocError(*doc, IDS_NOTCHANGED);
return;
}
doc->Revert();
}
}
//
/// Command enabler for CmViewCreate.
//
void
TDocManager::CeViewCreate(TCommandEnabler& hndlr)
{
TDocument* doc = GetCurrentDoc();
hndlr.Enable(doc != 0);
}
//
/// Calls CreateAnyView(*doc) where doc is the current document.
//
void
TDocManager::ViewCreate()
{
TDocument* doc = GetCurrentDoc();
if (doc)
CreateAnyView(*doc);
}
IMPLEMENT_STREAMABLE(TDocManager);
#if OWL_PERSISTENT_STREAMS
//
//
//
void*
TDocManager::Streamer::Read(ipstream& is, uint32 /*version*/) const
{
TDocManager* o = GetObject();
TDocTemplate* tpl = o->TemplateList;
for (;;) {
int isStatic;
is >> isStatic;
if (isStatic == -1)
break;
if (isStatic) {
if (tpl) { // if static templates available
is >> *tpl; // update static template data
tpl = o->GetNextTemplate(tpl);
}
else { // have run out of static templates
char tbuf[sizeof(TDocTemplate)]; // sink for unused template data
memset(tbuf, 0, sizeof tbuf); // force static flag off
is >> *(TDocTemplate*)tbuf;
}
}
else { // if dynamic template, object will be constructed
TModule* module;
is >> module;
is >> tpl;
tpl->SetModule(module);
o->AttachTemplate(*tpl);
}
}
int count;
is >> count; // document count
while (count--) {
TDocument* doc;
is >> doc;
doc->SetDocManager(*o); // inserts properly into list
}
// Get application, & post ourselves a wakeup message to finish things up
// once all windows have been created, etc.
//
o->Application = OWLGetAppDictionary().GetApplication(0);
TWindow* win = o->Application->GetMainWindow();
if (win && win->GetHandle())
win->PostMessage(WM_OWLWAKEUP);
return o;
}
//
//
//
void
TDocManager::Streamer::Write(opstream& os) const
{
TDocManager* o = GetObject();
TDocTemplate* tpl = 0;
while ((tpl = o->GetNextTemplate(tpl)) != 0) {
int flag = tpl->IsStatic();
os << flag;
if (flag) {
os << *tpl; // write reference to static template
}
else {
os << tpl->GetModule(); // write template's module pointer first
os << tpl; // write pointer to static template
}
}
os << -1; // template list terminator
TDocument* doc = 0;
int count;
for (count = 0; (doc = o->DocList.Next(doc))!=0; count++) ;
os << count;
// Must write documents out in order created, i.e. from end of list forward
//
while (count) {
int i = count--;
for (doc = 0; i--; doc = o->DocList.Next(doc)) ;
os << doc;
}
}
#endif
} // OWL namespace
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: TmplIndex.
↑ V1004 The 'tplList' pointer was used unsafely after it was verified against nullptr. Check lines: 427, 430.
↑ V1004 The 'tpl' pointer was used unsafely after it was verified against nullptr. Check lines: 465, 467.
↑ V1004 The 'tpl' pointer was used unsafely after it was verified against nullptr. Check lines: 489, 491.
↑ V1004 The 'doc' pointer was used unsafely after it was verified against nullptr. Check lines: 667, 669.
↑ V1004 The 'tpl' pointer was used unsafely after it was verified against nullptr. Check lines: 670, 674.
↑ V1004 The 'tpl' pointer was used unsafely after it was verified against nullptr. Check lines: 822, 824.
↑ V1048 The 'filepath[0]' variable was assigned the same value.
↑ V507 Pointer to local array 'filepath' is stored outside the scope of this array. Such a pointer will become invalid.
↑ V547 Expression 'index > 0' is always true.
↑ V730 It is possible that not all members of a class are initialized inside the constructor. Consider inspecting: NextViewId.
↑ V1004 The 'curDoc' pointer was used unsafely after it was verified against nullptr. Check lines: 1369, 1372.
↑ V1004 The 'path' pointer was used unsafely after it was verified against nullptr. Check lines: 1403, 1450.
↑ V524 It is odd that the body of 'CeFileOpen' function is fully equivalent to the body of 'CeFileNew' function.
↑ V774 The 'doc' pointer was used after the memory was released.