/*----------------------------------------------------------------------------*/ /* */ /* Copyright (c) 2008-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. */ /* */ /*----------------------------------------------------------------------------*/ /** * Name: displayWindowTree.rex * Type: Example ooRexx program * * Description: Allows the user to pick an open top-level window and then * displays the window hiearchy for that window. The program * uses both ooDialog and winsystm classes. * * This example uses some of the public functions provided by * the windowsSystem.frm package. That framework contains * functions shared with other example programs shipped with * ooRexx that use winsystm.cls. * * External function Source * --------------------------------------------------- * errorDialog() ooDialog * getWindowTree() windowsSystem.frm * showWindowTree() windowsSystem.frm * */ sd = locate() -- Use the global .constDir for symbolic IDs and turn auto detection off. .application~setDefaults("O", sd"winSystemDlgs.h", .false) -- Create and show our ooDialog dialog. The logic of the program is contained -- within the WindowListDlg class. dlg = .WindowListDlg~new(sd"winSystemDlgs.rc", IDD_WINDOW_List) if dlg~initCode == 0 then do dlg~execute("SHOWTOP") return 0 end else do msg = "Failed to instantiate the .WindowListDlg object." || '0d0a0d0a'x || - "Aborting on error." j = errorDialog(msg) return 99 end ::requires "windowsSystem.frm" ::class 'WindowListDlg' public subclass RcDialog /** initdialog() * Initialize the state of our dialog controls. */ ::method initDialog expose listView windows inError -- If some un-anticipated error happens we will change the behaviour of the -- dialog. inError is used to flag an error. inError = .false -- Instantiate an array that will be used to hold all the top-level window -- objects. windows = .array~new -- If we can't get the list view control, something is wrong. listView = self~newListView(IDC_LV_WINDOWS) if listView == .nil then return self~putInErrorState("NOLISTVIEW") -- The extended list view styles can only be added after the list view control -- has been created. -- -- The FULLROWSELECT style highlights the entire row when row is selected -- rather than just part of the row. -- -- The LABLETIP style will cause a tool-tip like label to appear that displays -- the entire text of the column, if the text is longer than will fit in the -- column, when the user puts their mouse over the row. listView~addExtendedStyle("FULLROWSELECT LABELTIP") -- We want to set the width of column 0, (the first column,) to the width of -- the list view control, minus the width of a scroll bar if there is one. -- -- We can find out the width of a scroll bar from the system metrics and can -- query the width of the list view control directly. -- -- Note that the system metric figure is in pixels and the column width needs -- to be in dialog units. Therefore the width of the scroll bar is more than -- we actually need, but it is close enough. parse value listView~getSize with width height SM_CXVSCROLL = 20 width -= SystemMetrics(SM_CXVSCROLL) -- Insert our one and only column for the list view control. listView~insertColumn(0, "Window Title", width) -- Connect the push buttons to our event handling methods. self~connectButton(IDC_PB_SHOW, onShow) self~connectButton(IDC_PB_QUIT, onQuit) self~connectButton(IDC_PB_REFRESH, onRefresh) -- The logic / code to fill the list view control is in the onRefresh() -- method. So, we simply invoke the method ourselves to populate the list -- view. self~onRefresh /** onRefresh() * This method contains the logic to populate the list view control with the * titles of the current top-level windows. The method is connected to the * Refresh button, so it is invoked when the user pushes that button. * * However, it can also be invoked internally to populate the list view. This * is done when the dialog is initialized, from the initDialog() method. And * it is also invokde if an invalid window handle is detected in the onShow() * method. */ ::method onRefresh expose listView windows inError -- Be sure the windows array is empty windows~empty -- Be sure the list view control is empty listView~deleteAll -- Instantiate a WindowManager object and get the desktop window. mgr = .WindowsManager~new deskTop = mgr~desktopWindow -- Build an array of all the children windows of the desktop. Skip any window -- that does not have a title or that is invisible. child = deskTop~firstChild do while child <> .nil if child~title~strip \== "", child~state~caselessWordpos("invisible") == 0 then windows~append(child) child = child~next end -- If we don't have any windows, something is wrong. if windows~isEmpty then return self~putInErrorState("NOWINDOWS") -- Now, for each window, add a row using the window title as the text for the -- row. do wnd over windows listView~addRow( , , wnd~title) end -- Select the first row, so that we are guaranteed that a row is selected. -- Note that the row numbers are zero-indexed. listView~select(0) /** onShow() * The user pushed the 'Show' button. In the unlikely event that we are in an * error state we will quit. Otherwise, we will display the window hiearchy of * the window the user selected. */ ::method onShow expose listView inError windows if inError then return self~cancel -- Get the row number selected. Note that we are guarenteed that a row is -- selected because we selected a row to begin with and we have provided no -- way for the user to deselect a row. Because of this we do not have to -- check for -1. Since the rows are zero-indexed, we add 1 to the selected -- row number, to produce the index into our array of windows. wnd = windows[listView~selected + 1] -- It is conceivable / possible that the user has closed a window since the -- time the list view was populated. This can be detected because the window -- state will be 'Illegal Handle.' if wnd~state == "Illegal Handle" then return self~badHandle -- Display the window hierarchy of the selected window. tree = getWindowTree(wnd) success = showWindowTree(tree) /** onQuit() * The user pushed the 'Quit' button. This is easy, just quit the dialog. */ ::method onQuit return self~cancel /** badHandle() * This private method is invoked when the user picks a window that has been * closed since the list view was originally populated. We tell the user the * problem and refresh the list view. */ ::method badHandle private expose listView -- Get the text of the selected item to use in the error message. title = listView~itemText(listView~selected) msg = "The window you selected appears to have been closed." || '0d0a0d0a'x || - "Window title:" title || '0d0a0d0a'x || - "The window list is being refreshed. Select a new window." j = infoDialog(msg) self~onRefresh return 0 /** putInErrorState() * This private method is used when some un-recoverable error is detected. * * It displays an error message to the user based on the reason for the error, * sets the error state flag, and tries to disable the Show push button. */ ::method putInErrorState private expose inError use strict arg reason inError = .true select when reason == "NOWINDOWS" then do msg = "For some reason no top-level windows were located." || '0d0a'x || - "This is not correct, the sample program is not" || '0d0a'x || - "executing correctly." end when reason == "NOLISTVIEW" then do msg = "An internal error is preventing this sample program" || '0d0a'x || - "from executing correctly. The ListControl object" || '0d0a'x || - "could not be obtained." end otherwise do msg = "The sample program is not executing correctly," || '0d0a'x || - "some unknown error." end end -- End select msg = msg || '0d0a0d0a'x || "Please just quit." j = errorDialog(msg) -- We will try to disable the 'Show' push button. But, if the dialog is not -- working correctly, it could be that this won't work. pb = self~newPushButton(IDC_PB_SHOW) if pb <> .nil then pb~disable return 0