/*----------------------------------------------------------------------------*/ /* */ /* 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