//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1995, 1996 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of class THelpFileManager & THelpContext
//----------------------------------------------------------------------------
 
#include <owl/pch.h>
 
#include <owl/hlpmanag.h>
#include <owl/applicat.h>
#include <owl/window.h>
#include <owl/framewin.h>
#include <owl/gadgetwi.h>
#include <owl/template.h>
 
#if !defined(OWL_HLPMANAG_RH)
# include <owl/hlpmanag.rh>
#endif
 
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
#endif
 
namespace owl {
 
OWL_DIAGINFO;
 
static tchar HtmlHelpDllName[] = _T("HHCTRL.OCX");
 
THtmlHelpDll::THtmlHelpDll()
:
   TModule(HtmlHelpDllName, true, true, false), // shouldLoad, mustLoad and !addToList
  DllCanUnloadNow(*this, "DllCanUnloadNow"),
  DllGetClassObject(*this, "DllGetClassObject"),
#ifdef UNICODE
  HtmlHelp(*this, "HtmlHelpW")
#else
  HtmlHelp(*this, "HtmlHelpA")
#endif
{
}
 
THlpPopup::THlpPopup(uint id)
{
  cbStruct       = sizeof(HH_POPUP);
  hinst         = 0;
  idString       = id;
  pszText       = 0;
  pt            = TPoint(-1,-1);
  clrForeground = static_cast<COLORREF>(-1); //JJH added static casts
  clrBackground = static_cast<COLORREF>(-1);
  rcMargins     = TRect(-1,-1,-1,-1);
  pszFont       = 0;
}
 
void
THlpWinType::SetStyle(int style)
{
  fsValidMembers |= HHWIN_PARAM_STYLES;
  dwStyles |= style;
}
 
void
THlpWinType::SetProperties(int prop)
{
  fsValidMembers |= HHWIN_PARAM_PROPERTIES;
  fsWinProperties |= prop;
}
 
void
THlpWinType::SetToolBarFlags(int flags)
{
  fsValidMembers |= HHWIN_PARAM_TB_FLAGS;
  fsToolBarFlags  |= flags;
}
 
void
THlpWinType::SetWindowsPos(const TRect& rect)
{
  fsValidMembers |= HHWIN_PARAM_TB_FLAGS;
  rcWindowPos  = rect;
}
 
//
/// Constructor. Saves the name of the help file and creates the global context
/// table.
//
THelpFileManager::THelpFileManager(const tstring& helpFileName)
:
  UseHTMLHelp(false),
  WinToHTML(true),
  HelpCursor(0),
  ContextHelp(false),
  HelpState(false),
  LastParent(0)
{
  SetHelpFile(helpFileName);
  ContextTable = new TContextList;
}
 
//
/// Deletes the allocated context table.
//
THelpFileManager::~THelpFileManager()
{
  delete ContextTable;
  delete HelpCursor;
}
 
//
/// Called by EvHelp() to activate the help file with the help context ID.
//
void
THelpFileManager::ActivateHelp(TWindow* /*window*/, int helpFileContextId, uint helpCmd)
{
  if (helpCmd == HELP_INDEX || helpCmd == HELP_CONTENTS)
    helpCmd = HELP_FINDER;
  TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
  if(UseHTMLHelp){
    if (app)
      HelpState = ToBool(HtmlHelp(app->GetMainWindow(), GetHelpFile().c_str(),
                                  helpCmd, helpFileContextId) != 0);
    else
      HelpState = ToBool(HtmlHelp(0, GetHelpFile().c_str(),
                                  helpCmd, helpFileContextId) != 0);
  }
  else{
    if (app)
      HelpState = ToBool(app->GetMainWindow()->WinHelp(GetHelpFile().c_str(),
                         helpCmd, helpFileContextId));
    else
      HelpState = ToBool(::WinHelp(0, GetHelpFile().c_str(),
                         helpCmd, helpFileContextId));
  }
}
 
//
/// Deactivates the help.
//
void
THelpFileManager::DeactivateHelp()
{
  TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
  if(UseHTMLHelp){
    if (app)
      HtmlHelp(app->GetMainWindow(), GetHelpFile().c_str(), HELP_QUIT, 0);
    else
      HtmlHelp(0, GetHelpFile().c_str(), HELP_QUIT, 0);
  }
  else{
    if (app)
      app->GetMainWindow()->WinHelp(GetHelpFile().c_str(), HELP_QUIT, 0);
    else
      ::WinHelp(0, GetHelpFile().c_str(), HELP_QUIT, 0);
  }
}
 
//
// Support for nwe HTML Help
//
HWND
THelpFileManager::HtmlHelp(TWindow* wnd, LPCTSTR lpszHelp, uint uCmd,  DWORD_PTR data)
{
  // translate uCommand into HTML command
  uint command = uCmd;
  if(WinToHTML){
    switch(uCmd){
      case HELP_FINDER:
        command = HH_HELP_FINDER;
        break;
      case HELP_CONTENTS:  //== HELP_INDEX
        command = HH_HELP_CONTEXT;    //
        break;
      case HELP_WM_HELP:
        command = HH_TP_HELP_WM_HELP;
        break;
      case HELP_CONTEXTMENU:
        command = HH_TP_HELP_CONTEXTMENU;
        break;
      case HELP_QUIT:
        command = HH_CLOSE_ALL;
        break;
      case HELP_CONTEXTPOPUP: {
//-----------------------
//Start Ole �nderung 02.04.2002
//          command = HH_TP_HELP_CONTEXTMENU;
               command = HH_DISPLAY_TEXT_POPUP;
          if(THtmlHelp::IsAvailable()){
                  if(LastHit == TPoint(-1, -1))
                    HtmlHelp(GetWindowPtr(GetDesktopWindow()), lpszHelp, HH_HELP_CONTEXT,data) ;
                  else
                  {
                    HH_POPUP hPop; // HTML Help popup structure
                    memset(&hPop, 0, sizeof(hPop));
                    hPop.cbStruct         = sizeof(hPop);
                    hPop.clrBackground    = -1;
                    hPop.clrForeground    = -1;
                    hPop.rcMargins.left   = -1;
                    hPop.rcMargins.bottom = -1;
                    hPop.rcMargins.right  = -1;
                    hPop.pt               = LastHit;
                    hPop.idString         = static_cast<UINT>(data);
                    hPop.pszText          = NULL;
                    hPop.pszFont          = NULL;
 
                    const HWND w = wnd ? wnd->GetHandle() : 0;
                    return THtmlHelp::Dll()->HtmlHelp(w, lpszHelp, command, reinterpret_cast<DWORD_PTR>(&hPop));
                  }
 
//            if(wnd)
//              return THtmlHelp::Dll()->HtmlHelp(*wnd,lpszHelp,command,data);
//            else
//              return THtmlHelp::Dll()->HtmlHelp(0, lpszHelp,command,data);
//Ende  Ole �nderung 02.04.2002
//-----------------------
          }
          return 0;
        }
    }
  }
  if(THtmlHelp::IsAvailable()){
    if(wnd)
      return THtmlHelp::Dll()->HtmlHelp(*wnd,lpszHelp,command,data);
    else
      return THtmlHelp::Dll()->HtmlHelp(0, lpszHelp,command,data);
  }
  return 0;
}
 
//
/// Changes the name of the help file.
//
void
THelpFileManager::SetHelpFile(const tstring& helpFileName)
{
  HelpFileName = helpFileName;
  UseHTMLHelp = false;
  LPCTSTR ptr = _tcsrchr(HelpFileName.c_str(),_T('.'));
  if(ptr && _tcsicmp(ptr, _T(".chm"))==0)
    UseHTMLHelp = true;
}
 
DEFINE_RESPONSE_TABLE1(THelpFileManager, TEventHandler)
  EV_COMMAND(CM_CONTEXTHELP,           CmContextHelp),
  EV_COMMAND_ENABLE(CM_CONTEXTHELP,   CeContextHelp),
  EV_COMMAND(CM_WHAT_IS_THIS,         CmWhatIsThis),
  EV_WM_HELP,
  EV_OWLHELPHIT,
END_RESPONSE_TABLE;
 
//
//
//
void
THelpFileManager::SetHelpCursor()
{
  if(!HelpCursor){
    TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
    if(app)
      HelpCursor = new TCursor(*app, TResId(IDC_HELPCURSOR));
  }
  ::SetCursor(*HelpCursor);
}
 
//
//
//
void
THelpFileManager::CmContextHelp ()
{
  ContextHelp = true;
   SetHelpCursor();
}
 
//
//
//
void
THelpFileManager::CeContextHelp (TCommandEnabler& ce)
{
  ce.Enable(true);
}
 
//
//
//
void
THelpFileManager::CmWhatIsThis()
{
  PRECONDITION(LastParent);
  if(!LastParent)
    return;
  LastParent->ScreenToClient(LastHit); // TWindow
  HWND hWnd = LastParent->ChildWindowFromPoint(LastHit);
  HELPINFO Info;
  Info.cbSize       = sizeof(Info);
  Info.MousePos     = LastHit;
 
  if(hWnd){
    TGadgetWindow* gwin = TYPESAFE_DOWNCAST(GetWindowPtr(hWnd), TGadgetWindow);
    if(gwin){
      TGadget* gd = gwin->GadgetFromPoint(LastHit);
      if(gd){
        Info.iContextType = HELPINFO_MENUITEM;
        Info.iCtrlId      = gd->GetId();
        EvHelp(Info);
      }
      return;
    }
  }
  Info.iContextType = HELPINFO_WINDOW;
  Info.dwContextId  = 0;
 
  // If the click wasn't on one of the controls, open Help for dialog.
  if (hWnd == 0 || hWnd == LastParent->GetHandle()){
    Info.iContextType = HELPINFO_MENUITEM;
    Info.iCtrlId      = IDHELP;
    Info.hItemHandle  = LastParent->GetHandle();
  }
  else{
    Info.iCtrlId      = ::GetDlgCtrlID(hWnd);
    Info.hItemHandle  = hWnd;
  }
  EvHelp(Info);
}
 
//
/// Event handler for the WM_HELP message.
//
void
THelpFileManager::EvHelp(const HELPINFO& hi)
{
  THelpContext context;
  bool success = false;
  uint hlpCmd = HELP_CONTEXTPOPUP;
 
  if (hi.iContextType == HELPINFO_MENUITEM){
    success = GetHelpContextFromMenu(context, hi.iCtrlId);
    hlpCmd = HELP_CONTEXT;
  }
  else if (hi.iContextType == HELPINFO_WINDOW)
    success = GetHelpContextFromControl(context, hi.iCtrlId, (HWND)hi.hItemHandle);
 
  LastHit = hi.MousePos;
  if (::GetKeyState(VK_F1) < 0 && ::GetKeyState(VK_SHIFT) < 0)
  {
    TWindow* wnd = context.GetWindow();
    TWindow* child = wnd->ChildWithId(hi.iCtrlId);
    LastHit = TPoint(wnd->GetWindowAttr().X + child->GetWindowAttr().X, wnd->GetWindowAttr().Y + child->GetWindowAttr().Y);
  }
  else if(::GetKeyState(VK_F1) < 0)
    LastHit = TPoint(-1, -1);
 
  if (success)
    ActivateHelp(context.GetWindow(), context.GetHelpFileContextId(), hlpCmd);
}
 
//
//
//
bool
THelpFileManager::ProcessHelpMsg (MSG& msg)
{
  if (msg.message == WM_COMMAND) {
    // help command from menu or from gadget from "what this?" for gadget
    if (ContextHelp || (::GetKeyState(VK_F1) < 0)) {
      ContextHelp = false;
      HELPINFO Info;
      Info.cbSize       = sizeof(Info);
      Info.iContextType = HELPINFO_MENUITEM;
      Info.iCtrlId      = static_cast<int>(msg.wParam);
      Info.dwContextId  = 0;
      EvHelp(Info);
      return true;
    }
  }
  else{
    switch (msg.message) {
      case WM_KEYDOWN :
        if (msg.wParam == VK_F1) {
          // If the Shift/F1 then set the help cursor and turn on the modal help state.
          if (::GetKeyState(VK_SHIFT) < 0 && !ContextHelp) {
            CmContextHelp();
            return true;        // Gobble up the message.
          }
        }
        else {
          if (ContextHelp && (msg.wParam == VK_ESCAPE)) {
            ContextHelp = false;
            TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
            if (app)
              app->GetMainWindow()->SetCursor(0, IDC_ARROW); //?????????????????
            return true;    // Gobble up the message.
          }
        }
        break;
 
      case WM_MOUSEMOVE :
      case WM_NCMOUSEMOVE :
        if(ContextHelp){
          SetHelpCursor();
          return true;        // Gobble up the message.
        }
        break;
 
      case WM_INITMENU :
        if(ContextHelp) {
           SetHelpCursor();
          return true;        // Gobble up the message.
        }
        break;
 
      case WM_ENTERIDLE :
        if(msg.wParam == MSGF_MENU)
          if (GetKeyState(VK_F1) < 0) {
            ContextHelp = true;
            TApplication* app = TYPESAFE_DOWNCAST(this, TApplication);
            if (app)
              app->GetMainWindow()->PostMessage(WM_KEYDOWN, VK_RETURN, 0L);
            return true;       // Gobble up the message.
          }
        break;
 
      default :
        ;
    }  // End of switch
  }
  // Continue normal processing.
  return false;
}
 
//
/// Return true if the control id is the same as the context entry's control id.
//
static bool
MatchControlId(const THelpContext& context, int controlId, HWND hwnd)
{
  if (context.GetControlContextId() == controlId &&
      context.GetWindow() && context.GetWindow()->IsChild(hwnd)) {
    return true;
  }
  return false;
}
 
//
/// Returns true if a match for the control ID was found.
//
bool
THelpFileManager::GetHelpContextFromControl(THelpContext& context,
                                            int controlId, HWND hwnd) const
{
  // for each item in the context table
  //
  for(TContextListIterator iterator(*ContextTable); iterator; iterator++){
    context = iterator.Current();
 
    // try to match the control id
    //
    if (IsIndirectHelpContext(context)) {
      THelpContext* indirect = (THelpContext*)context.GetWindow();
      while (!IsLastIndirectContext(*indirect)) {
        if (MatchControlId(*indirect, controlId, hwnd)) {
          context = *indirect;
          return true;
        }
        indirect++;
      }
    }
    else if (MatchControlId(context, controlId, hwnd))
      return true;
  }
  return false;
}
 
//
/// Return true if the menu item identifier matches a context entry's menu
/// item identifier.
//
static bool
MatchMenuId(const THelpContext& context, int menuId)
{
  if (context.GetMenuContextId() == menuId) {
    return true;
  }
  return false;
}
 
//
/// Returns true if a match for the menu item ID was found.
//
bool
THelpFileManager::GetHelpContextFromMenu(THelpContext& context, int menuId) const
{
  // for each item in the context table
  //
  for (TContextListIterator iterator(*ContextTable); iterator; iterator++) {
    context = iterator.Current();
 
 
    // try to match the menu item identifier
    //
    if (IsIndirectHelpContext(context)) {
      THelpContext* indirect = (THelpContext*)context.GetWindow();
      while (!IsLastIndirectContext(*indirect)) {
        if (MatchMenuId(*indirect, menuId)) {
          context = *indirect;
          return true;
        }
        indirect++;
      }
    }
    else if (MatchMenuId(context, menuId))
      return true;
  }
  return false;
}
 
//
/// Adds an entry into the global context table.
//
void
THelpFileManager::AddContextInfo(TWindow* window, int helpId, int menuId, int controlId)
{
  ContextTable->Add(THelpContext(window, helpId, menuId, controlId));
}
 
static bool
WindowsEqual(const THelpContext& context, void* ptr)
{
  TWindow* targetWindow = (TWindow*)ptr;
  if (context.GetWindow() == targetWindow)
    return true;
  return false;
}
 
//
/// Removes all the entries in the context table for the window.
//
void
THelpFileManager::RemoveContextInfo(TWindow* window)
{
  THelpContext* context = ContextTable->FirstThat(WindowsEqual, window);
  while (context) {
    ContextTable->DetachItem(*context);
    context = ContextTable->FirstThat(WindowsEqual, window);
  }
  if (ContextTable->Empty())
    DeactivateHelp();
}
 
//
/// Default constructor that initializes every data member to zero.
//
THelpContext::THelpContext()
:
  Window(0),
  HelpFileContextId(0),
  MenuContextId(0),
  ControlContextId(0)
{
}
 
//
/// Convenient constructor to initialize the context entry with the
/// proper ids.
//
THelpContext::THelpContext(TWindow* window, int helpId, int menuId, int controlId)
:
  Window(window),
  HelpFileContextId(helpId),
  MenuContextId(menuId),
  ControlContextId(controlId)
{
}
 
//
/// Makes a copy of the context entry.
//
THelpContext::THelpContext(const THelpContext& other)
{
  *this = other;
}
 
//
// Do nothing.
//
THelpContext::~THelpContext()
{
}
 
//
/// Makes a copy of the context entry.
//
THelpContext&
THelpContext::operator =(const THelpContext& other)
{
  HelpFileContextId = other.GetHelpFileContextId();
  MenuContextId     = other.GetMenuContextId();
  ControlContextId  = other.GetControlContextId();
  Window            = other.GetWindow();
  return *this;
}
 
//
/// Returns true if the context entries match.
//
bool
THelpContext::operator ==(const THelpContext& other) const
{
  return Window == other.GetWindow() &&
         HelpFileContextId == other.GetHelpFileContextId() &&
         MenuContextId == other.GetMenuContextId() &&
         ControlContextId == other.GetControlContextId();
}
//
//
//
bool
THelpContext::operator <(const THelpContext& other) const
{
  return HelpFileContextId < other.GetHelpFileContextId();
}
 
} // OWL namespace
/* ========================================================================== */
 

V1037 Two or more case-branches perform the same actions. Check lines: 402, 409

V1027 Pointer to an object of the 'TWindow' class is cast to unrelated 'THelpContext' class.

V1027 Pointer to an object of the 'TWindow' class is cast to unrelated 'THelpContext' class.

V522 There might be dereferencing of a potential null pointer 'HelpCursor'.

V832 It's better to use '= default;' syntax instead of empty destructor body.

V803 Decreased performance. In case 'iterator' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.

V803 Decreased performance. In case 'iterator' is iterator it's more effective to use prefix form of increment. Replace iterator++ with ++iterator.