221 lines
10 KiB
Rexx
Executable File
221 lines
10 KiB
Rexx
Executable File
/*----------------------------------------------------------------------------*/
|
|
/* */
|
|
/* 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
|