/*----------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 2011-2014 Rexx Language Association. All rights reserved.    */
/*                                                                            */
/* This program and the accompanying materials are made available under       */
/* the terms of the Common Public License v1.0 which accompanies this         */
/* distribution. A copy is also available at the following address:           */
/* https://www.oorexx.org/license.html                                        */
/*                                                                            */
/* Redistribution and use in source and binary forms, with or                 */
/* without modification, are permitted provided that the following            */
/* conditions are met:                                                        */
/*                                                                            */
/* Redistributions of source code must retain the above copyright             */
/* notice, this list of conditions and the following disclaimer.              */
/* Redistributions in binary form must reproduce the above copyright          */
/* notice, this list of conditions and the following disclaimer in            */
/* the documentation and/or other materials provided with the distribution.   */
/*                                                                            */
/* Neither the name of Rexx Language Association nor the names                */
/* of its contributors may be used to endorse or promote products             */
/* derived from this software without specific prior written permission.      */
/*                                                                            */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT          */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS          */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,        */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               */
/*                                                                            */
/*----------------------------------------------------------------------------*/
/* ooDialog User Guide - Support
   Exercise 08: View.rex

   ViewMixin							  v01-02 18Jun13
   ---------
   A mixin superclass for View components (part of the Model-View Framework).

   Contains: 	   class: "ViewMixin"

   Description: A mixin superclass for all xxxView components.

   Pre-requisites: MVF.

   Outstanding Problems: None reported.

   Changes:
     v01-00 12May13: First Version.
     v01-01 06Jun13: Added drag/drop methods. Also store model id as an
                     attribute ('myModel') to save subclases having to do it.
                     Note - some drag/drop methods are there as catch-alls for
                     when a subclass does not implement them. Default action
                     still to be verified.
            18Jun13: Changed "drop" method to "dmDrop" and "pickup" to "dmPickup"
                     (both sent to DragMgr).

------------------------------------------------------------------------------*/

::REQUIRES "ooDialog.cls"
::REQUIRES "support\Component"

/*//////////////////////////////////////////////////////////////////////////////
  ==============================================================================
  ViewMixin						  	  v01-00 13May13
  ---------
  A mixin superclass for View classes.  the Order Management dialog. Handles interest registration,
  = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

--::CLASS View SUBCLASS RcDialog PUBLIC
::CLASS View PUBLIC MIXINCLASS PlainBaseDialog

  ::ATTRIBUTE viewMgr
  ::ATTRIBUTE objectMgr
  ::ATTRIBUTE dragMgr
  ::ATTRIBUTE myModel

  /*----------------------------------------------------------------------------
    initView - initialises the mixin instance - invoked from ???
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    --::method init  -- Results in hang!
  ::METHOD initView
    --say "View-initView-01."
    self~objectMgr = .local~my.ObjectMgr	-- Needed to clear up when dialog closed.
    self~viewMgr = .local~myViewMgr
    -- Direct Manipulation:
    self~dragMgr = .local~my.DragMgr
    --say "View-initView-01: dragMgr =" self~dragMgr

    return
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /*----------------------------------------------------------------------------
    activate - must be invoked by subclass.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD activate UNGUARDED
    expose viewClass viewInstance		-- needed for tidy-up on close.
    use arg modelId
    -- Store model id for use by subclasses:
    self~myModel = modelId
    --say "View-activate-01: self =" self
    -- Get View Instance name and View Class for tidy-up when dialog is closed.
    viewInstance = self~identityHash
    dlgName = self~objectName
    parse var dlgName . viewClass
    modelData = modelId~query
    --say "View-activate-02."
    return modelData
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /*----------------------------------------------------------------------------
    showModel - forwards to ObjectMgrloadList - for invocation by subclasses.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD showModel
    use strict arg  modelClass, modelInstance, parentDlg
    r = self~ObjectMgr~showModel(modelClass, modelInstance, parentDlg)
    if r = .false then say "View-showModel - ObjectMgr returned .false."
    return r
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /*----------------------------------------------------------------------------
    loadList - must be invoked by subclass.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  --::METHOD loadList Wait till check out how do ShowModel for List.
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


  /*----------------------------------------------------------------------------
    leaving - invoked by ooDialog when a dialog closes.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD leaving UNGUARDED
    expose viewClass viewInstance
    --say "View-leaving-01. objectMgr =" objectMgr
    self~objectMgr~removeView(viewClass, viewInstance)
    self~dragMgr~removeDlg(self) 		-- closing, so tell DragManager
    -- Note - we do not remove the Model. Should we? If so, not from here!
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


  /*----------------------------------------------------------------------------
    Popup Offsets
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    setOffsetParent - set the parent dialog id for later offsetting of a child
                      dialog.
         **** Note: This method not used in Exercise07. ****                  */
  ::METHOD setOffsetParent
    use strict arg parentDlg
    viewMgr = .local~my.ViewMgr
    viewMgr~parentOffsetDlg = self

  /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    offset - offsets a "child" dialog from its "parent" dialog (i.e. the dialog
             from which the child is "popped up").
         **** Note: This method not used in Exercise07. ****                  */
  ::METHOD offset
    --say "RcView-offset-1."
    offset    = .local~my.ViewMgr~dlgOffset
    parentDlg = .local~my.ViewMgr~parentOffsetDlg
    popupPos  = parentDlg~getRealPos
    popupPos~incr(offset,offset)
    self~moveTo(popupPos, "SHOWWINDOW")
    self~ensureVisible()

  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /*----------------------------------------------------------------------------
    initDialog - invokes offset.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD initDialog
    say "ViewMixin-initDialog-01."
    self~offset
  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */


  /*----------------------------------------------------------------------------
    Drag/Drop Methods
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

  /*----------------------------------------------------------------------------
    dmSetAsSource - called by a view component to define itself as a drag source.
		    Typically invoked from subclass' initDialog method.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD dmSetAsSource PRIVATE		-- DM setup method
    -- Each source dialog should invoke this only once.
    -- Invoking it more than once may well result in errors.
    -- Note: a dialog may be both source and target.
    expose mouse dmSourceControl sourceWin
    use arg dmSourceCursorFile, dmSourceArea, dmSourceControl
    if dmSourceCursorFile = .nil then do
      say "View-dmSetAsSource-00:" .HRS~dmSrcNulCursor
      return .false
    end
    --say "View-dmSetAsSource-01: dmSourceCursorFile, dmSourceArea, dmSourceControl:"
    --say "   '"||dmSourceCursorFile||"', "||dmSourceArea", "||dmSourceControl

    if dmSourceArea = "DMSOURCEAREA" then do		-- set default pickup area
      dmSourceArea = self~clientRect()
      dmSourceArea~left += 10; dmSourceArea~top += 10; -
        dmSourceArea~right -= 10; dmSourceArea~bottom -= 10
      --say "View-dmSetAsSource-02 - default pickup client area =" dmSourceArea
    end
    --else say "View-dmSetAsSource-03 - pickup client area =" dmSourceArea

    if dmSourceControl = "DMSOURCECONTROL" then do 	-- The source is a dialog.
      --say "View-dmSetAsSource-04: source is a dialog."
      sourceWin = self
      mouse = .Mouse~new(sourceWin)
      mouse~connectEvent('MOUSEMOVE',dmOnMove)
      mouse~connectEvent('LBUTTONDOWN', dmOnLBdown)
      mouse~connectEvent('LBUTTONUP', dmOnLBup)
      --self~dragMgr~setSource(self, mouse, dmSourceCursorFile, dmSourceArea, .nil)
      self~dragMgr~setSource(self, mouse, dmSourceCursorFile, dmSourceArea, self)  -- ***
    end
    else do					        -- The source is a control (such as a ListView).
      --say "View-dmSetAsSource-05: source is a control."
      sourceWin = dmSourceControl
      mouse = .Mouse~new(dmSourceControl)
      mouse~connectEvent('MOUSEMOVE',dmOnMove)
      mouse~connectEvent('LBUTTONDOWN', dmOnLBdown)
      mouse~connectEvent('LBUTTONUP', dmOnLBup)
      --self~dragMgr~setSource(self, mouse, dmSourceCursorFile, dmSourceArea, dmSourceControl)
      self~dragMgr~setSource(sourceWin, mouse, dmSourceCursorFile, dmSourceArea, self)  -- ***
    end
    --mouse~connectEvent('MOUSELEAVE', dmLeave)
    --say "View-dmSetAsSource-06: source is:" sourceWin


    return .true

  /*----------------------------------------------------------------------------
    dmSetAsTarget - called by a view component to define itself as a drag target.
		    Typically invoked from subclass' initDialog method.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD dmSetAsTarget				-- DM setup method
    -- Each target dialog should invoke this only once.
    -- Invoking it more than once may well result in errors.
    -- Note: a dialog may be both source and target.
    expose dmIsTargetDlg
    use arg dmDropArea
    --say "View-dmSetAsTarget-01."

    if dmDropArea = "DMDROPAREA" then do		-- set default. Better is to check the type.
      dmDropArea = self~clientRect()
      dmDropArea~left += 10; dmDropArea~top += 10; dmDropArea~right -= 30; dmDropArea~bottom -= 30
    end

    self~dragMgr~setTarget(self, self~hwnd, dmDropArea)

    return .true

  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  ::METHOD dmOnLBdown
    expose sourceWin
    use arg keyState, mousePos
    --say "View-dmOnLBdown-00; self, keystate, mousePos =" self||"," keystate||"," mousePos
    info = self~dmGetItemInfo				-- for listviews
    if info = 0 then nop --say "View-dmOnLBdown-01 - info is zero."

    else do
      nop --say "View-dmOnLBdown-02; info, sourceWin =" info||"," sourceWin
      -- store the info somewhere - how about "drag data"?.
      -- Drag data = classname, instance name.
    end
    --self~DragMgr~dmPickup(self, keyState, mousePos, dragData) - not right yet
    self~DragMgr~dmPickup(sourceWin, keyState, mousePos)  -- pre-listview
    return 0

  ::METHOD dmGetItemInfo	-- Dummy method for when sublcass does not
                                -- implement it.
    return 0


  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  ::METHOD dmOnMove
    expose sourceWin
    use arg keyState, mousePos
    --say "View-dmOnMove: self, sourceWin =" self||"," sourceWin
    self~dragMgr~moving(sourceWin, self, keystate, mousePos)
    --say "View-dmOnMove"
    return 0

  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  ::METHOD dmOnLBup
    use arg keyState, mousePos
    --say "View-dmOnLBup-01; self =" self
    self~dragMgr~dmDrop(self, keyState, mousePos)
    --return r -- throws error, as done no return at all.
    return 0
    say 'DMSource-onLButtonUp: the mouse is at ('mousePos~x',' mousePos~y') with these qualifiers:' keyState

  -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/*  ::METHOD dmNeverDrop
    -- Invoked by a target object to prevent any drop (e.g. if a sales order is
    -- complete and should not now be altered). The red/white target icon is
    -- changed to grey.
    expose dmTargetIconImage dmIcons dmTargetInactive
    use arg dmTargetInactive
    if dmTargetInactive then dmTargetIconImage~setImage(dmIcons[dmTgtInactiveIcon])
    else dmTargetIconImage~setImage(dmIcons[dmTgtReadyIcon])
*/

  ::METHOD dmQueryDrop
    use arg dmSourceDlg, mousePos
    --say "View-dmQueryDrop-01."
    return .true			-- Default is to accept the drop.

  ::METHOD dmDrop
    use arg sourceDlg
    --say "View-dmDrop-01."
    return .true

/*  ::METHOD cancel
    expose dmDragMgr
    say "View-Cancel-01."
    dmDragMgr~removeDlg(self) 		-- closing, so tell DragManager
    return self~cancel:super
*/
/*
  ::METHOD ok
    say "View-ok-01."
    self~dragMgr~removeDlg(self) 		-- closing, so tell DragManager
    return self~ok:super
*/


  /*----------------------------------------------------------------------------
    Event Management Methods. *** INCOMPLETE ***
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

    /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  --::METHOD triggerEvent
  --  use strict arg event
  --  idEventMgr = .local~my.EventMgr

  /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  ::METHOD viewDoIt
    --say "View-viewDoIt-01."


/*============================================================================*/



/*==============================================================================
  Human-Readable Strings (HRS)					  v00-01 13Jan12
  --------
   The HRS class provides constant character strings for user-visible messages.
  = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */

::CLASS HRS PRIVATE		-- Human-Readable Strings
  ::CONSTANT dmSrcNulCursor  "View-dmSetAsSource - Error: Source Cursor is null."
  ::CONSTANT dmTgtBadParam   "View-dmSetAsTarget - Error: null dlg or null hwnd or both."


