/*----------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 2013-2022 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.               */
/*                                                                            */
/*----------------------------------------------------------------------------*/

/**
 * An example showing usage of the BrowseForFolder class.  This example shows
 * how to use the class to browse virtual folders, in this case the Printers
 * folder.
 *
 * The BrowseForFolder object puts up the same Windows Shell browse dialog as
 * does the SimpleFolderBrowse object, but it is much more configurable.
 *
 * This example uses the browse for folder dialog to let the user select a
 * printer.
 *
 * The example puts up a regular dialog and on the push of a button shows the
 * browse for folder dialog set to browse only printers.  The user's pick is
 * is displayed in an edit box.
 */

    -- Set up some symbolic IDs and then put up our example dialog.
    .application~setDefaults('O', , .false)
    .constDir[IDC_PB_BROWSE]      = 100
    .constDir[IDC_ST_RESULTS]     = 101
    .constDir[IDC_EDIT]           = 102
    .constDir[IDC_RB_LONG_NAME] = 103
    .constDir[IDC_RB_SHORT_NAME]  = 104

    dlg = .PrintersDialog~new
    dlg~execute("SHOWTOP", IDI_DLG_OOREXX)

    return 0

::requires "ooDialog.cls"

::class 'PrintersDialog' subclass UserDialog

/** init()
 *
 *  Typical UserDialog init() method.  Initializes the super class, the starts
 *  the dialog template by creating the frame in the template.  Internally, the
 *  create() method will invoke the define() method.  When create() returns,
 *  the dialog template will be complete.
 */
::method init
  forward class (super) continue

  self~create(30, 30, 257, 123, "Browse For Printers Example", "CENTER")


/** define()
 *
 *  A typical define() method for a UserDialog.  We create a push button in the
 *  dialog template that allows the user to show the browse for folder dialog.
 *
 *  An edit control and two radio buttons are created, the edit control shows
 *  the result of the user's selection in the browse for folder dialog.  The
 *  radio button control how the selection is returned from the browse for
 *  folder dialog.
 */
::method defineDialog

    self~createStaticText(IDC_ST_RESULTS, 10, 10, 30, 11, , "Results:")
    self~createEdit(IDC_EDIT, 10, 24, 237, 11, 'AUTOSCROLLH')
    self~createRadioButton(IDC_RB_LONG_NAME, 10, 60, 90, 14, "AUTO", 'Long Display Name')
    self~createRadioButton(IDC_RB_SHORT_NAME, 10, 79, 90, 14, "AUTO", 'Short Display Name')
    self~createPushButton(IDC_PB_BROWSE, 10, 99, 65, 14, "DEFAULT", "Browse Printers", onBrowse)
    self~createPushButton(IDCANCEL, 197, 99, 50, 14, , "Done")


/** onBrowse()
 *
 * The event handler for the Browse Printers push button.  We configure a
 * BrowseForFolder object, display it, and report the user's actions in the edit
 * control.
 *
 * The Windows Shell keeps track of things in the shell using a structure called
 * an 'item ID list.'  Every thing in the shell has an item ID list.  Most
 * things in the shell have a corresponding file system path.  But not every
 * thing.  Virtual folders like the printer objects do not have a file system
 * path.
 *
 * The getFolder() method returns the file system path picked by the user.  That
 * method can not return a value for a virtual folder, so it returns .nil.  To
 * get the printer the user picks, we need to use the getItemIDList() method.
 * This method returns the handle to an item ID list.
 *
 * Currently, the programmer can not do much with an item ID list handle.  This
 * may change in future versions of ooDialog.  However, the programmer can get
 * the display name of the shell item through the item ID list, which is what
 * we do here.
 *
 * Like most, if not all, handles in Windows, the item ID list handle represents
 * a system resource that has been allocated by the OS.  When the Rexx
 * programmer is done with the item ID list, it is good practice to release the
 * handle to free up the system resources used by the item ID list.
 */
::method onBrowse unguarded
    expose rbShort edit

    -- Set title, banner, and a hint for the dialog.
    title  = 'Browse For a Printer'
    banner = 'Select the printer to use for this test.'
    hint   = 'This is only a demonstration, no printing will be done.'

    bff = .BrowseForFolder~new(title, banner, hint)

    -- Make this dialog the owner window of the browse dialog.  The root for the
    -- browse dialog will be the virtual Printers folder.  If that is not set,
    -- the user will not see the printers.  In addition, we want the user to
    -- only see the printers.  That way, if the dialog is not canceled, we are
    -- sure a printer was picked and not some random folder.
    bff~owner = self
    bff~root = 'CSIDL_PRINTERS'

    -- Set non-default options for the browse dialog.  We need the browse for
    -- printers option.  The operating system will not allow a new folder to be
    -- created in the virtual printers folder, so it disables the Make New
    -- Folder button.  It looks better to just remove the button altogether.
    bff~options = 'BROWSEFORPRINTER NONEWFOLDERBUTTON'

    -- The getItemIDList() method is what actually puts up the browse for folder
    -- dialog.  Normally, by default, the getItemIDList() will release the COM
    -- resources used our BrowseForFolder object.  But, we still need the COM
    -- resources to be able to use the getDisplayName() method.  So, we tell the
    -- method we still need COM active by passing in .true to the method.
    --
    -- We we tell the object we still need COM, it then becomes our
    -- responsibility to release COM.  If the user cancels, we release COM and
    -- return.  Otherwise, we release COM further down in this method when we
    -- are finished with COM.
    pidl = bff~getItemIDList(.true)
    if pidl == .nil then do
        edit~setText('The user canceled.')
        bff~releaseCOM
        return 0
    end

    -- Decide what the format for the returned display name.  With no arguments,
    -- the getDisplayName() method will try to return the most complete name.
    -- For a folder with a file system path, that will be a fully qualified
    -- path name.  For a virtual folder, the name will include the parent
    -- folder(s) of the actual folder picked.
    --
    -- The second optional argument to getDisplayName() specifies the format of
    -- the returned name.  Normal display will be just the printer name.
    if rbShort~checked then do
        name = bff~getDisplayName(pidl, 'NORMALDISPLAY')
    end
    else do
        name = bff~getDisplayName(pidl, 'DESKTOPABSOLUTEEDITING')
    end

    -- We are done with pidl, release it.
    bff~releaseItemIDList(pidl)

    -- We are done with the BrowseForFolder object.  Since we told the
    -- getItemIDList() method to not release the COM resources, we need to
    -- explicitly do it ourself.
    bff~releaseCOM

    -- Determine text for the edit control ...
    if name == .nil then do
        text = 'Unexpected result. ' .DlgUtil~errMsg(.systemErrorCode)
    end
    else do
        text = 'The user picked: ' name
    end

    -- ... and set it
    edit~setText(text)

    return 0


/** initDialog()
 *
 * Simple init dialog method.  We get references to the edit control and one of
 * the two radio buttons.  Since the radio buttons are auto and there are only 2
 * of them we only need one reference to be able to tell which is checked.
 */
::method initDialog
    expose rbShort edit

    edit = self~newEdit(IDC_EDIT)
    rbShort = self~newRadioButton(IDC_RB_SHORT_NAME)
    rbShort~check
