// ****************************************************************************
// OWL Extensions (OWLEXT) Class Library
// Copyright (C) 1998 by Dieter Windau
// All rights reserved
//
// ctxhelpm.cpp: implementation file
// Version: 1.2
// Date: 20.10.1998
// Author: Dieter Windau (used with permission)
//
// TCtxHelpFileManager is a freeware OWL class derived from THelpFileManager
// that add context sensitive help functions similar to the context help
// generated by AppWizard (MFC) or AppExpert (OWL).
//
// TCtxHelpStatusBar is a freeware OWL class that support context sensitive help
//
// You are free to use/modify this code but leave this header intact.
// May not be sold for profit.
//
// Tested with Borland C++ 5.02, OWL 5.02 under Windows NT 4.0 SP3 but I think
// the class would work with Windows 95 too.
// This file is provided "as is" with no expressed or implied warranty.
// Use at your own risk.
//
// Please send me bug reports, bug fixes, enhancements, requests, etc., and
// I'll try to keep this in next versions:
// EMail: dieter.windau@usa.net
// Web: http://www.members.aol.com/softengage/index.htm
// ****************************************************************************
#include <owlext\pch.h>
#pragma hdrstop
#include <owlext/ctxhelpm.h>
#include <owl/filename.h>
#include <owl/framewin.h>
#include <owl/dialog.h>
#include <owlext/ctxhelpm.rh>
using namespace owl;
namespace OwlExt {
DIAG_DEFINE_GROUP_INIT(OWL_INI, CtxHelp, 1, 0);
// private function
TModule* FindResourceModule(TWindow* parent, TModule* module, TResId resId, LPCTSTR type);
// ************************* TCtxHelpFileManager ******************************
DEFINE_RESPONSE_TABLE1(TCtxHelpFileManager, THelpFileManager)
EV_COMMAND(CM_HELPCONTENTS, CmHelpContents),
EV_COMMAND(CM_HELPCONTEXT, CmHelpContext),
EV_COMMAND_ENABLE(CM_HELPCONTEXT, CeHelpContext),
EV_COMMAND(CM_HELPUSING, CmHelpUsing),
EV_COMMAND(CM_HELPSEARCH, CmHelpSearch),
EV_WM_HELP,
END_RESPONSE_TABLE;
TCtxHelpFileManager::TCtxHelpFileManager(const owl::tstring& helpFileName)
:
THelpFileManager(helpFileName)
{
SupportSystemMenu = false;
SupportSimpleF1Help = true;
::LoadString(*FindResourceModule(0,0,IDS_HINTTEXT/16+1,RT_STRING),
IDS_HINTTEXT, HintText, 128);
// the help cursor is a windows wide default cursor
//
hHelpCursor = ::LoadCursor(0, IDC_HELP);
hOldCursor = 0;
// it is better to hold the full absolute path for the help file
// because, if the actual path changed, the help file isn't found
//
owl::tstring str;
TCHAR fullPath[_MAX_PATH];
::GetModuleFileName(NULL, fullPath, sizeof(fullPath));
TFileName ExeFileName(fullPath);
TFileName HelpFileName;
if(!GetHelpFile().empty())
HelpFileName = GetHelpFile();
// if there is no device and path, us the applicatin device and path
//
if (!(HelpFileName.HasParts(TFileName::Server | TFileName::Device) &&
HelpFileName.HasParts(TFileName::Path))) {
if (ExeFileName.HasParts(TFileName::Server | TFileName::Device) &&
ExeFileName.HasParts(TFileName::Path)) {
str = ExeFileName.GetParts(
TFileName::Server | TFileName::Device | TFileName::Path);
}
}
else
str = HelpFileName.GetParts(
TFileName::Server | TFileName::Device | TFileName::Path);
// if the is no filename, use the application name
//
if (!HelpFileName.HasParts(TFileName::File)) {
if (ExeFileName.HasParts(TFileName::File))
str += ExeFileName.GetParts(TFileName::File);
}
else
str += HelpFileName.GetParts(TFileName::File);
// if there is no extension, use the default extension ".hlp"
//
if (!HelpFileName.HasParts(TFileName::Ext))
str += TEXT(".hlp");
else
str += HelpFileName.GetParts(TFileName::Ext);
// Set only the the new HelpFile, if the file exist
//
TFileName filename(str);
if (filename.Exists())
SetHelpFile(str);
TRACEX(CtxHelp, 0, "TCtxHelpFileManager constructed @" << (void*)this);
}
TCtxHelpFileManager::~TCtxHelpFileManager()
{
TRACEX(CtxHelp, 0, "TCtxHelpFileManager destructed @" << (void*)this);
}
void TCtxHelpFileManager::WinHelp(UINT helpID)
// Call WinHelp in mode CONTEXT_HELP with helpID
// If ContextHelp is true, after the call the context help is set to false
{
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (app) {
app->GetMainWindow()->WinHelp(GetHelpFile().c_str(), HELP_CONTEXT, helpID);
if (IsContextHelp())
SetContextHelp(false);
}
}
// Call a yellow popup help window for dialog windows
// and the normal online help for other windows or menus
//
void TCtxHelpFileManager::ActivateHelp(TWindow* wnd, int contextId, uint hlpCmd)
{
uint cmd = HELP_CONTEXT;
if (hlpCmd == HELP_INDEX || hlpCmd == HELP_CONTENTS)
cmd = HELP_FINDER;
#if !defined(BI_COMP_MSC)
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (app) {
if (wnd) {
TDialog* dlg = TYPESAFE_DOWNCAST(wnd, TDialog);
if (dlg) {
app->GetMainWindow()->WinHelp(GetHelpFile().c_str(),
HELP_CONTEXTPOPUP, contextId);
return;
}
}
app->GetMainWindow()->WinHelp(GetHelpFile().c_str(), cmd, contextId);
}
else
#endif
::WinHelp(0, GetHelpFile().c_str(), cmd, contextId);
}
void TCtxHelpFileManager::CmHelpContents()
{
// Show the help table of contents.
//
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (app)
app->GetMainWindow()->WinHelp(GetHelpFile().c_str(), HELP_CONTENTS, 0);
else
::WinHelp(0, GetHelpFile().c_str(), HELP_CONTENTS, 0);
}
void TCtxHelpFileManager::CmHelpContext()
{
// turn context sensitive help on / off
//
SetContextHelp((ContextHelp) ? false : true);
}
void TCtxHelpFileManager::CeHelpContext(TCommandEnabler& ce)
{
ce.SetCheck(ContextHelp);
}
void TCtxHelpFileManager::CmHelpUsing()
{
// Display help on help
//
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (app)
app->GetMainWindow()->WinHelp(GetHelpFile().c_str(), HELP_HELPONHELP, 0);
else
::WinHelp(0, GetHelpFile().c_str(), HELP_HELPONHELP, 0);
}
void TCtxHelpFileManager::CmHelpSearch()
{
const tchar* EmptyString = _T("");
// Display the seach dialog of help with Empty string
//
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (app)
app->GetMainWindow()->WinHelp(GetHelpFile(), HELP_PARTIALKEY,
reinterpret_cast<ULONG_PTR>(EmptyString));
}
bool TCtxHelpFileManager::PreProcessAppMsg(HWND hwnd, uint msg,
WPARAM wParam, LPARAM lParam)
// Process application messages to provide context sensitive help
{
MSG aMSG;
aMSG.hwnd = hwnd;
aMSG.message = msg;
aMSG.wParam = wParam;
aMSG.lParam = lParam;
return PreProcessAppMsg(aMSG);
}
bool TCtxHelpFileManager::PreProcessAppMsg(MSG& msg)
// Process application messages to provide context sensitive help
{
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (!(app))
return false;
switch (msg.message) {
case WM_COMMAND:
if (ContextHelp) {
WinHelp(static_cast<uint>(msg.wParam));
return true; // Gobble up the message.
}
break;
case WM_SYSCOMMAND: // context sensitive help for system menu command
if (ContextHelp && SupportSystemMenu) {
if (msg.wParam == SC_SIZE ||
msg.wParam == SC_MOVE ||
msg.wParam == SC_MINIMIZE ||
msg.wParam == SC_MAXIMIZE ||
msg.wParam == SC_NEXTWINDOW ||
msg.wParam == SC_PREVWINDOW ||
msg.wParam == SC_CLOSE ||
msg.wParam == SC_RESTORE ||
msg.wParam == SC_TASKLIST ||
msg.wParam == SC_HSCROLL ||
msg.wParam == SC_VSCROLL) {
WinHelp(static_cast<uint>(msg.wParam));
return true; // Gobble up the message.
}
}
break;
case WM_NCLBUTTONDOWN: // context sensitive help for application decorations
if (ContextHelp && SupportSystemMenu) {
DWORD dwHelpContextId = 0;
switch (msg.wParam) {
case HTZOOM: dwHelpContextId = SC_MAXIMIZE; break;
case HTREDUCE: dwHelpContextId = SC_MINIMIZE; break;
case HTCAPTION: dwHelpContextId = HID_TITLEBAR; break;
case HTVSCROLL: dwHelpContextId = SC_VSCROLL; break;
case HTHSCROLL: dwHelpContextId = SC_HSCROLL; break;
case HTSYSMENU: // allow the menus to popup
case HTMENU: break;
case HTBOTTOM:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
case HTTOP:
case HTLEFT:
case HTRIGHT:
case HTTOPLEFT:
case HTTOPRIGHT: dwHelpContextId = SC_SIZE; break;
}
if (dwHelpContextId != 0) {
WinHelp(dwHelpContextId);
return true; // Gobble up the message.
}
}
break;
case WM_KEYDOWN:
if (ContextHelp && msg.wParam == VK_ESCAPE) {
// turn the context sensitive help off
//
SetContextHelp(false);
return true; // Gobble up the message.
}
// BEGIN HARDCODE ACCELERATORS
//
// If you have other accelerators in your app delete this section
//
if (msg.wParam == VK_F1) {
if (::GetKeyState(VK_SHIFT) < 0) {
// If Shift+F1 call the CmHelpContext() function
//
CmHelpContext();
return true; // Gobble up the message.
}
else if (::GetKeyState(VK_CONTROL) < 0) {
// If Ctrl+F1 call the CmHelpSearch() function
//
if (!ContextHelp)
CmHelpSearch();
return true; // Gobble up the message.
}
else {
// If only F1 call the CmHelpContents() function
//
SetContextHelp(false);
CmHelpContents();
return true; // Gobble up the message.
}
}
//
// END HARDCODE ACCELERATORS
break;
// case WM_LBUTTONDOWN: // catch this messages in all windows
// case WM_NCLBUTTONDOWN: // that has a context sensitive help
// e.g. statusbar, client window
case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
case WM_NCRBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_RBUTTONDBLCLK:
case WM_NCMBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_MBUTTONDBLCLK:
case WM_INITMENU:
if (ContextHelp) {
if (::GetCursor() != hHelpCursor)
::SetCursor(hHelpCursor);
return true; // Gobble up the message.
}
break;
case WM_MENUSELECT:
if ((HIWORD(msg.wParam) & MF_POPUP) && msg.lParam) {
// Use TMenu, because the GetMenuItemID function returns
// a value-1 if the menu is a popup menu
//
TMenu menu((HMENU)msg.lParam);
MenuItemId = menu.GetMenuItemID(LOWORD(msg.wParam));
}
break;
default:
break;
} // end of switch
return false;
}
void TCtxHelpFileManager::SetContextHelp(bool contextHelp)
{
if (ContextHelp != contextHelp) {
ContextHelp = contextHelp;
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (!(app))
return;
TCtxHelpStatusBar* statusBar = TYPESAFE_DOWNCAST(
app->GetMainWindow()->ChildWithId(IDW_STATUSBAR), TCtxHelpStatusBar);
if (ContextHelp) {
hOldCursor = ::SetCursor(hHelpCursor);
if (statusBar) {
statusBar->SetHintText(HintText);
statusBar->Block();
}
}
else {
::SetCursor(hOldCursor);
hOldCursor = 0;
if (statusBar) {
statusBar->UnBlock();
statusBar->ClearHintText(); // Restore text of status bar
}
}
}
}
void TCtxHelpFileManager::EvHelp(const HELPINFO& hi)
// Copy more or less from THelpFileManager. Add simple help support for menus
{
THelpContext context;
bool success = false;
if (hi.iContextType == HELPINFO_MENUITEM)
success = GetHelpContextFromMenu(context, hi.iCtrlId);
else if (hi.iContextType == HELPINFO_WINDOW)
success = GetHelpContextFromControl(context, hi.iCtrlId,
(HWND)hi.hItemHandle);
if (success)
ActivateHelp(context.GetWindow(), context.GetHelpFileContextId());
else {
// if there isn't a entry in the table
//
if (SupportSimpleF1Help && hi.iContextType == HELPINFO_MENUITEM) {
// support simple F1 help (menu commandid = helpid)
//
TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
if (app) {
// show only help for system menu commands, if they are supported
//
if ((SupportSystemMenu == false) && (
hi.iCtrlId == SC_SIZE ||
hi.iCtrlId == SC_MOVE ||
hi.iCtrlId == SC_MINIMIZE ||
hi.iCtrlId == SC_MAXIMIZE ||
hi.iCtrlId == SC_NEXTWINDOW ||
hi.iCtrlId == SC_PREVWINDOW ||
hi.iCtrlId == SC_CLOSE ||
hi.iCtrlId == SC_RESTORE ||
hi.iCtrlId == SC_TASKLIST))
return;
if (hi.iCtrlId == 0) {
// Activate help with the id, that is copied in WM_MENUSELECT
//
ActivateHelp(app->GetMainWindow(), MenuItemId);
}
else
ActivateHelp(app->GetMainWindow(), hi.iCtrlId);
}
}
}
}
// ************************* TCtxHelpStatusBar ********************************
DEFINE_RESPONSE_TABLE1(TCtxHelpStatusBar, TStatusBar)
EV_WM_LBUTTONDOWN,
END_RESPONSE_TABLE;
TCtxHelpStatusBar::TCtxHelpStatusBar(TWindow* parent,
TGadget::TBorderStyle borderStyle,
uint modeIndicators,
TFont* font,
TModule* module):
TStatusBar(parent, borderStyle, modeIndicators, font, module)
{
block = false;
TRACEX(CtxHelp, 0, "TCtxHelpStatusBar constructed @" << (void*)this);
}
TCtxHelpStatusBar::~TCtxHelpStatusBar()
{
TRACEX(CtxHelp, 0, "TCtxHelpStatusBar destructed @" << (void*)this);
}
void TCtxHelpStatusBar::SetHintText(const owl::tstring& text)
// Show only the hint text, if the output is not blocked
{
if (block == false)
TStatusBar::SetHintText(text);
}
void TCtxHelpStatusBar::SetHintText(int i)
{
PRECONDITION(i == 0); InUse(i);
ClearHintText();
}
void TCtxHelpStatusBar::EvLButtonDown(uint modKeys, const TPoint& point)
{
TCtxHelpFileManager* ctxHelpM = TYPESAFE_DOWNCAST(GetApplication(),
TCtxHelpFileManager);
// Show help only, if the ContextHelp is true and the help for system menu
// and application decorations is supported
//
if (ctxHelpM && ctxHelpM->IsContextHelp() && ctxHelpM->IsSupportSystemMenu()) {
ctxHelpM->WinHelp(IDW_STATUSBAR);
}
else
TStatusBar::EvLButtonDown(modKeys, point);
}
} // OwlExt namespace
//==============================================================================
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: MenuItemId.
↑ V530 The return value of function 'LoadStringA' is required to be utilized.
↑ V688 The 'HelpFileName' local variable possesses the same name as one of the class members, which can result in a confusion.