001package org.vishia.gral.base; 002 003import java.text.ParseException; 004import java.util.LinkedList; 005import java.util.List; 006import java.util.concurrent.atomic.AtomicInteger; 007 008import org.vishia.byteData.VariableAccessWithIdx; 009import org.vishia.byteData.VariableAccess_ifc; 010import org.vishia.byteData.VariableContainer_ifc; 011import org.vishia.gral.ifc.GralColor; 012import org.vishia.gral.ifc.GralFont; 013import org.vishia.gral.ifc.GralMngBuild_ifc; 014import org.vishia.gral.ifc.GralMng_ifc; 015import org.vishia.gral.ifc.GralRectangle; 016import org.vishia.gral.ifc.GralSetValue_ifc; 017import org.vishia.gral.ifc.GralUserAction; 018import org.vishia.gral.ifc.GralWidgetCfg_ifc; 019import org.vishia.gral.ifc.GralWidget_ifc; 020import org.vishia.gral.impl_ifc.GralWidgetImpl_ifc; 021import org.vishia.gral.widget.GralHorizontalSelector; 022import org.vishia.util.Assert; 023import org.vishia.util.Debugutil; 024import org.vishia.util.KeyCode; 025 026 027 028/**This class is the base class of representation of a graphical widget in the gral concept. 029 * All widgets in the gral concept have this base data independent of the implementation graphic. 030 * The implementation graphic should have a wrapper class inherited from {@link ImplAccess} which 031 * contains specials of the implementation and refers the widget of the implementation layer graphic, 032 * for example a text field. 033 * <br><br> 034 * Any widget is represented in the user's level by a derived instance of a {@link GralWidget}. 035 * There are 2 strategies yet to create widgets in respect to the graphical implementation. 036 * Either the Widget is created independent of the graphic implementation first 037 * and then taken as parameter for the graphic widget-creating method. In this case the GralWidget 038 * contains nothing of the graphic implementation but has a reference to it. 039 * The second strategy yet is, the Widget is returned by the graphic-implementation widget-creating method 040 * as a instance which has {@link GralWidget} and its non-graphic specializations as super class 041 * and the graphic depending parts in the created instance. 042 * <br><br> 043 * The first form is more universal. Especially generic can be used for the class definition if necessary. 044 * It us used yet only (2013-06) for 045 * <ul> 046 * <li>{@link org.vishia.gral.widget.GralHorizontalSelector#setToPanel(GralMngBuild_ifc)} 047 * <li>{@link GralTable#setToPanel(GralMngBuild_ifc)}. 048 * </ul> 049 * but it may be used more and more in the future. The <code>setToPanel(GralMng)</code> method 050 * invokes the graphic implementation specific derivation of the {@link GralMng}, which creates 051 * the implementation widgets. <br> 052 * For the UML presentation see {@link org.vishia.util.Docu_UML_simpleNotation}: 053 * <pre> 054 * 055 * GralHorizontalSelector< UserType > <-----<*>UserCanCreateIt_GraphicIndependently 056 * - some special non-graphic data 057 * | 058 * |<------------------------------------------------------------------data---| 059 * | | 060 * |&<--------&GraphicImplAccess<|---+ | 061 * | | | 062 * +--|>GralWidget | | 063 * | | | | 064 * | |<>--->GralWidgImpl_ifc<|---+--SwtHorizontalSelector | 065 * | | | | 066 * | | | | 067 * |<*>------------------------>swt.Canvas 068 * | | 069 * | | 070 * -paintRoutine <-------paintListener---| 071 * -mouseListener<-------mouseListener---| 072 * -etc. 073 * 074 * </pre> 075 * <br><br> 076 * The user creates an instance of {@link GralHorizontalSelector} in any thread maybe as composite, 077 * it is independent of the graphic itself. 078 * Then the user builds its graphic appearance with invocation of {@link GralHorizontalSelector#setToPanel(GralMngBuild_ifc)} 079 * with the derived instance of {@link GralMng} as parameter. 080 * <br><br> 081 * The <code>GralWidget</code> knows the graphic implementation via the {@link GralWidgImpl_ifc} to invoke some methods 082 * for the graphical appearance. The interface is independent 083 * of the implementation itself. The implementor of this interface for this example 084 * is the {@link org.vishia.gral.swt.SwtHorizontalSelector} implements this methods. 085 * <br><br> 086 * The SwtHorizontalSelector refers the platform-specific widget Object (Swing: javax.swing.JComponent, 087 * org.eclipse.swt.widgets.Control etc.), in this case a {@link org.eclipse.swt.widgets.Canvas}. 088 * It contains the special paint routines, mouse handling etc. 089 * <br><br> 090 * The platform-specific widget has a reference to the GralWidget, in this case the {@link GralHorizontalSelector} 091 * stored as Object-reference. This reference can be used in the paintRoutine, mouseListerner etc. to get 092 * information about the GralWidget. 093 * <br><br> 094 * The second form takes most of the characteristics as parameters for the creating method. 095 * It needs inheritance. 096 * <pre> 097 * GralButton <-------UserCanAssociate it but can't create the instance with constructor. 098 * | 099 * |-------------|>SwtButton 100 * </pre> 101 * The instance is Graphic-Implementation-specific and it is created with this interface as factory:<br> 102 * {@link #addButton(String, GralUserAction, String)}. 103 * <br><br> 104 * The ObjectModelDiagram may shown the relations:<br> 105 * <img src="../../../../../img/Widget_gral.png"><br> 106 * In this graphic the relationship between this class and the graphical implementation layer widget 107 * is shown with the example 'text field' in SWT: 108 * <ul> 109 * <li>The class {@link GralTextField} is the derived class of this to represent a text field 110 * in an implementation independent way. 111 * <li>The class {@link org.vishia.gral.swt.SwtTextFieldWrapper} is the implementor for the GralTextField 112 * for SWT graphic. 113 * <li>That implementor knows is SWT-specific and refers the SWT widget {@link org.eclipse.swt.widgets.Text} 114 * It based on the SWT-specific {@link org.eclipse.swt.widgets.Widget}. 115 * </ul> 116 * <br> 117 * The implementation layer widget should to be deal with this GralWidget because of some overridden 118 * methods of the implementation layer widget need that. The general contract is, 119 * that the implementation layer widget refers this GralWidget in its commonly user data field. 120 * For SWT it is {@link org.eclipse.swt.widgets.Widget#setData(Object)} method. 121 * <br><br> 122 * The Widget knows its {@link GralPos} at its panel where it is placed. The panel knows all widgets 123 * which are placed there (widgetList). 124 * 125 * 126 * <br> 127 * <br> 128 * <b>Change a widget from application in any thread</b>:<br> 129 * The user can invoke the methods of the widget to animate it in a GUI etc, for example {@link #setBackColor(GralColor, int)} 130 * or {@link #setValue(int, int, Object)}. This methods can be called in any thread. This concept is described with the 131 * method {@link #setText(CharSequence)}, appropriate for all set methods. 132 * 133 * 134 * <br> 135 * <br> 136 * <b>Concept of data binding</b><br> 137 * 2012-05-19 138 * <br> 139 * <img src="../../../../../img/WidgetVariable_gral.png"><br> 140 * A widget has 2 associations: {@link #variable} and {@link #variables} to a management class {@link VariableAccessWithIdx} 141 * which knows the user data via a commonly {@link VariableAccess_ifc}. The data can be existing in the 142 * user space with this interface. That part of user software doesn't know the graphical view of the data. 143 * The graphical part of software calls any refresh of showing, it calls the method {@link #refreshFromVariable(VariableContainer_ifc)} 144 * for all visible widgets. With this the widget gets the data from user with the variable associations 145 * and prepares it for the proper appearance depending on the kind of widget, format String etc. 146 * <br><br> 147 * The association to the correct variable is given only with a String as argument of the {@link #setDataPath(String)} 148 * method. The variable is found with the second interface {@link VariableContainer_ifc} which should be known 149 * by the graphical part of software and which is one parameter of the {@link #refreshFromVariable(VariableContainer_ifc)} method. 150 * The conclusion between the String given variable name or path and the data can be supplied in any form 151 * in the users software, which knows the data. 152 * <br><br> 153 * The data can be coming from any remote device. In that kind there are two ways to get the actually values: 154 * <ol> 155 * <li>There is a cyclically communication. The remote device sends all data in a cycle maybe some 100 milliseconds. 156 * Then the actual data are present. The superior control should be call the {@link #refreshFromVariable(VariableContainer_ifc)}-method 157 * if the data are received yet or in any other proper cycle. 158 * <li>The data are requested from the remote device only if they are need either for displaying in widgets 159 * of for other reasons. This kind of data holding are proper especially if they are a lot of data, 160 * not all of them should be communicated any time. 161 * </ol> 162 * For the second approach a time of actuality and a time of requesting are used. The method {@link #requestNewValueForVariable(long)} 163 * can be used to force communication. 164 * <br><br> 165 * <b>Strategy of changing the graphical content of a widget</b>:<br> 166 * See {@link GralWidget_ifc} 167 * <br><br> 168 * <b>Strategy to create widgets and positioning</b>: see {@link GralMng.GralMngFocusListener}. 169 * 170 * @author Hartmut Schorrig 171 * 172 */ 173public class GralWidget implements GralWidget_ifc, GralSetValue_ifc, GetGralWidget_ifc 174{ 175 176 /**Version, history and license. 177 * <ul> 178 * <li>2016-09-30 Hartmut bugfix: {@link #setFocus()} has set the default focus of the primaryWindow if the focus of a window was set. 179 * <li>2016-09-30 Hartmut New idea, concept: {@link ImplAccess#wdgimpl}: That refers an implementation of a WidgetHelper class of the implementation layer 180 * which knows the widget. Via this aggregation some action with the implementation widget can be do which are defined 181 * in the {@link GralWidgetImpl_ifc}. See {@link org.vishia.gral.swt.SwtWidgetHelper}. 182 * <li>2016-09-18 Hartmut chg: {@link #getActionChangeStrict(org.vishia.gral.ifc.GralWidget_ifc.ActionChangeWhen, boolean)} documented, 183 * changed: returns not null if strict and when==null and a common action is given. Earlier: Returns null in that case. 184 * <li>2016-09-02 Hartmut chg: {@link GralWidget#GralWidget(String, String, char)} with a position String is now deprecated. 185 * Instead the {@link GralWidget#GralWidget(String, char)} which was deprecated till now is the favor again, but with a combination 186 * of "@pos=name" as first argument. That can be used for all derived widgets!. Therewith it is more simple to complete the widgets 187 * with the capability of usage of a position String. Without "@...=" it is the old behavior of the constructor. 188 * Note that the position can be given with {@link GralMng#setPosition(GralPos, float, float, float, float, int, char)} etc. too, 189 * with numeric values which may be calculated, instead a constant text. 190 * <li>2016-08-31 Hartmut new: {@link #isGraphicDisposed()} especially used for GralWindow-dispose detection. 191 * <li>2016-07-20 Hartmut chg: invocation of registerWidget one time after its position is known. Either it is in the ctor of GralWidget 192 * or it is in the ctor of {@link GralWidget.ImplAccess} if the position was assigned later in the graphic thread. 193 * <li>2016-07-20 Hartmut chg: instead setToPanel now {@link #createImplWidget_Gthread()}. It is a better name. 194 * <li>2016-07-03 Hartmut chg: {@link #createImplWidget_Gthread()}: If the _wdgImpl is initialized already, this method does nothing. Before: Exception 195 * <li>2016-07-03 Hartmut refact: actionChange: Now the {@link GralWidget_ifc.ActionChange} describes the action class and arguments. 196 * {@link ConfigData#actionChange1} refers the only one change action, or {@link ConfigData#actionChangeSelect} contains more as one change action. 197 * {@link #specifyActionChange(String, GralUserAction, String[], org.vishia.gral.ifc.GralWidget_ifc.ActionChangeWhen...)} sets the only one or special actions, 198 * {@link #getActionChange(org.vishia.gral.ifc.GralWidget_ifc.ActionChangeWhen)} selects a proper one. 199 * All derived widgets and implementation are adapted to the new system. The user interface is nearly identical. 200 * <li>2016-07-03 Hartmut chg: it is not derived from {@link GralWidgImpl_ifc} any more. It was the old concept: An implementing widgets was derived from the GralWidget. 201 * The new concept is: An implementing widget is derived from its derived class of {@link GralWidget.ImplAccess}. Therefore only that base class implements the GralWidgetImpl_ifc. 202 * <li>2016-07-03 Hartmut chg: handling of visible: A GralWidget is invisible by default. {@link #setVisible(boolean)} should be invoked on creation. 203 * It is possible that widgets are switched. All widgets of a non-visible tab of a tabbed panel are set to invisible, especially {@link #bVisibleState} = false. 204 * The {@link #isVisible()} is checked to decide whether a widget should be updated in the inspector. Only visible widgets should be updated. 205 * The {@link GralWidgImpl_ifc#setVisibleGThread(boolean)} is implemented to all known widgets for the implementation layer in the kind of {@link #setFocusGThread()}. 206 * See documentation on the methods. 207 * <li>2015-09-20 Hartmut chg: some final methods now non final, because they have to be overridden for large widgets. 208 * <li>2015-09-20 Hartmut chg: gardening for {@link DynamicData#getChanged()}, now private attribute {@link DynamicData#whatIsChanged} 209 * <li>2015-09-20 Hartmut new: {@link #setActionMouse(GralMouseWidgetAction_ifc, int)} was a private thing in {@link org.vishia.gral.swt.SwtGralMouseListener.MouseListenerGralAction} 210 * for widget implementation's mouse handling. Now as user define-able property of any widget, especially use-able for text fields. 211 * <li>2015-09-12 Hartmut new: {@link #getData()}, {@link #setData(Object)} was existent as {@link GralWidget#setContentInfo(Object)}, 212 * now explicit property of any widget. {@link GralWidget#setContentInfo(Object)} was an older approach, not in interface, now deprecated. 213 * <li>2015-06-21 Hartmut bugfix: {@link #setFocus(int, int)} had hanged because while-loop on same window panel for a parent. 214 * <li>2015-01-27 Hartmut new: {@link DynamicData#bTouchedField}, {@link ImplAccess##setTouched()} especially for a text field 215 * if any editing key was received. Then the GUI-operator may mark a text or make an input etc. The setting of the text 216 * from a cyclically thread should be prevented then to prevent disturb the GUI-operation. If the focus was lost then this bit 217 * is reseted. It is an important feature for GUI-handling which was missed up to now. 218 * Yet only used for {@link GralTextField#setText(CharSequence, int)}. It may prevent repaint for universally usage for all widgets. 219 * <li>2015-01-27 Hartmut new: method {@link #getVariable(VariableContainer_ifc)} instead {@link #getVariableFromContentInfo(VariableContainer_ifc)}. 220 * The last one method is used in an application but it does not run well for all requirements. The code of {@link #getVariable(VariableContainer_ifc)} 221 * is copied from the well tested {@link #refreshFromVariable(VariableContainer_ifc)} as own routine and then used in a new application. 222 * <li>2014-01-15 Hartmut new: {@link #getCmd(int)} with options. 223 * <li>2014-01-03 Hartmut new: {@link #isInFocus()} 224 * <li>2013-12-21 Hartmut chg: {@link #repaint()} invokes redraw immediately if it is in graphic thread. 225 * It invokes {@link #repaint(int, int)} with the {@link #repaintDelay} if it is not in graphic thread. 226 * It does nothing if the implementation layer widget is not created yet. It means it can invoked 227 * without parameter in any case. 228 * <li>2013-12-21 Hartmut chg: {@link ImplAccess#setDragEnable(int)} and setDropEnable moved from the core class. 229 * It is adapt after change {@link GralTextField}. 230 * <li>2013-12-21 Hartmut new: {@link #setToPanel(GralMngBuild_ifc)} is final now and invokes 231 * {@link GralMngBuild_ifc#createImplWidget_Gthread(GralWidget)}. That method handles all widget types. 232 * <li>2013-11-11 Hartmut new: {@link #refreshFromVariable(VariableContainer_ifc, long, GralColor, GralColor)} 233 * which shows old values grayed. 234 * <li>2013-11-11 Hartmut chg: {@link #setFocus()} searches the {@link GralTabbedPanel} where the widget is 235 * member of and invokes its {@link GralTabbedPanel#selectTab(String)}. It is not correct that the graphic 236 * implementation layer does that itself. 237 * <li>2013-06-29 Hartmut new: {@link #setToPanel(GralMngBuild_ifc)} as common method. 238 * <li>2013-06-16 Hartmut new {@link #_wdgImpl}. This instance was present in the past but removed. The concept is re-activated 239 * because a graphic-implementation-independent GralWidget instance can have any generic types 240 * and can be created as composite (with final type name = new Type(...)). 241 * See comments of class {@link GralMngBuild_ifc}. 242 * <li>2013-03-13 Hartmut new {@link #getContentIdent()}, {@link #setContentIdent(long)} 243 * <li>2013-03-13 Hartmut new {@link #bShouldInitialize} 244 * <li>2012-09-24 Hartmut chg: {@link #getName()} now returns {@link #sDataPath} or {@link #sCmd} if the other info are null. 245 * <li>2012-09-24 Hartmut chg: {@link #refreshFromVariable(VariableContainer_ifc)} for long and double values. 246 * <li>2012-09-17 Hartmut new {@link ConfigData} and {@link #cfg}, used yet only for {@link ConfigData#showParam}. 247 * <li>2012-09-17 Hartmut chg whatIsChanged#whatIsChanged} moved from {@link GralTextField}. The concept is valid for all widgets 248 * in cohesion with the concept of the whatIsChanged}. 249 * <li>2012-09-17 Hartmut chg {@link #setActionShow(GralUserAction, String[])} now with parameters. 250 * 251 * <li>2012-08-21 Hartmut new {@link DynamicData} and {@link #dyda} for all non-static widget properties, the dynamic data 252 * are that data which are used for all widget types in runtime. TODO: store the configuration data (all other) in an 253 * inner class CfgData or in a common class cfgdata see {@link org.vishia.gral.cfg.GralCfgData}. 254 * <li>2012-08-21 The method {@link #setBackColor(GralColor, int)}, {@link #setLineColor(GralColor, int)} and {@link #setTextColor(GralColor)} 255 * are declared in the {@link GralWidget_ifc} yet and implemented here using {@link #dyda}. 256 * <li>2012-07-29 Hartmut chg: {@link #setFocus()} and {@link #setFocus(int, int)} can be called in any thread yet. 257 * <li>2012-04-25 Hartmut some enhancements 258 * <li>2012-04-07 Hartmut chg: {@link #refreshFromVariable(VariableContainer_ifc)} regards int16, int8 259 * <li>2012-04-01 Hartmut new: {@link #refreshFromVariable(VariableContainer_ifc)}. A GralWidget is binded now 260 * more to a variable via the new {@link VariableAccessWithIdx} and then to any {@link VariableAccess_ifc}. 261 * It is possible to refresh the visible information from the variable. 262 * <li>2012-01-04 Hartmut new: {@link #repaintDelay}, use it. 263 * <li>2012-03-31 Hartmut new: {@link #isVisible()} and {@link ImplAccess#setVisibleState(boolean)}. 264 * renamed: {@link #implMethodWidget_} instead old: 'gralWidgetMethod'. 265 * <li>2012-03-08 Hartmut chg: {@link #repaintRequ} firstly remove the request from queue before execution, 266 * a new request after that time will be added newly therefore, then execute it. 267 * <li>2012-02-22 Hartmut new: catch on {@link #repaintGthread()} and continue the calling level 268 * because elsewhere the repaint order isn't removed from the {@link org.vishia.gral.base.GralGraphicThread#addDispatchOrder(GralGraphicTimeOrder)}-queue. 269 * <li>2012-02-22 Hartmut new: implements {@link GralSetValue_ifc} now. 270 * <li>2012-01-16 Hartmut new Concept {@link #repaint()}, can be invoked in any thread. With delay possible. 271 * All inherit widgets have to be implement {@link #repaintGthread()}. 272 * <li>2011-12-27 Hartmut new {@link #setHtmlHelp(String)}. For context sensitive help. 273 * <li>2011-11-18 Hartmut bugfix: {@link #setFocusGThread()} had called {@link GralMng#setFocus(GralWidget)} and vice versa. 274 * Instead it should be a abstract method here and implemented in all Widgets. See {@link org.vishia.gral.swt.SwtWidgetHelper#setFocusOfTabSwt(org.eclipse.swt.widgets.Control)}. 275 * <li>2011-10-15 Hartmut chg: This class is now abstract. It is the super class for all wrapper implementations. 276 * The wrapper implements special interfaces for the kind of widgets. It is more simple for usage, less instances to know. 277 * A GralWidget is able to test with instanceof whether it is a special widget. The element widget is removed because the reference 278 * to the implementation widget will be present in the derived classes. 279 * <li>2011-10-01 Hartmut new: method {@link #setFocusGThread()}. It wrappes the {@link GralMng_ifc#setFocus(GralWidget)}. 280 * <li>2011-09-18 Hartmut chg: rename from WidgetDescriptor to GralWidget. It is the representation of a Widget in the graphic adapter 281 * inclusive some additional capabilities in comparison to basic graphic widgets, like {@link #sFormat} etc. 282 * <li>2011-09-11 Hartmut chg: rename itsPanel to {@link #itsMng}. The original approach was, that the PanelManager manages only one panel 283 * then one window. Now the GralPanelMng manages all panels of one application. It is instantiated only one time. 284 * Therefore this association isn't the associated panel where the widget is member of. 285 * <li>2011-09-08 Hartmut new: method {@link #setLineColor(GralColor, int)}. 286 * Background: Any widget have a background. Most of widgets have lines. The color of them 287 * should be able to animate if user data are changed. 288 * <li>2011-09-04 Hartmut new: method {@link #setBackColor(GralColor, int)}. 289 * <li>2011-08-14 Hartmut chg: {@link #widget} is now type of {@link GralWidget_ifc} and not Object. 290 * Generally it is the reference to the implementing code of the widget. The implementing code 291 * may based on a graphic base widget (SWT: Control) and implements the {@link GralWidget_ifc}, 292 * or it references the graphic base widget instance. The class {@link SwtWidgetSimpleWrapper} 293 * is able to wrap simple graphical base widget instances. 294 * <li>2011-08-13 Hartmut new: WidgetDescriptor now contains the position of the widget. 295 * It is used for resizing of large widgets. 296 * A large widget is a widget, which lengthens over the panel and it is changed in size with panel size change. 297 * A typical example is a text-area-widget. 298 * <li>2011-06-20 Hartmut new: method {@link #gralMng()} It is the panel manager! 299 * <li>2011-05-26 Hartmut new: separate action in {@link #actionChanging} and {@link #actionShow}. 300 * The actionChanging was the old action. It was called from the listener of the widgets of the underlying graphic 301 * if any changing is done on the widget (mouse click etc). But the actionShow is necessary too 302 * to prepare values to animate widgets without knowledge of the special kind of widget. The application 303 * should call only the actionShow, all specifics should be done in the action. 304 * <li>2011-05-22 Hartmut new: The Widget knows its {@link #itsCfgElement} now if it is present. 305 * It is possible to configurate widgets with the GralDesigner up to now. 306 * <li>2011-05-14 Hartmut chg: The WidgetDescriptor is now non-generic. 307 * Older Concept: Store the GUI implementation widget type as generic type there. 308 * But now a widget is stored as Object and it is casted in the implementation. It is more simple 309 * because the type is only used and the casting is only necessary in the implementation level. 310 * <li>2011-06-00 Hartmut created 311 * </ul> 312 * 313 * <b>Copyright/Copyleft</b>:<br> 314 * For this source the LGPL Lesser General Public License, 315 * published by the Free Software Foundation is valid. 316 * It means: 317 * <ol> 318 * <li> You can use this source without any restriction for any desired purpose. 319 * <li> You can redistribute copies of this source to everybody. 320 * <li> Every user of this source, also the user of redistribute copies 321 * with or without payment, must accept this license for further using. 322 * <li> But the LPGL is not appropriate for a whole software product, 323 * if this source is only a part of them. It means, the user 324 * must publish this part of source, 325 * but doesn't need to publish the whole source of the own product. 326 * <li> You can study and modify (improve) this source 327 * for own using or for redistribution, but you have to license the 328 * modified sources likewise under this LGPL Lesser General Public License. 329 * You mustn't delete this Copyright/Copyleft inscription in this source file. 330 * </ol> 331 * If you intent to use this source without publishing its usage, you can get 332 * a second license subscribing a special contract with the author. 333 * 334 * @author Hartmut Schorrig = hartmut.schorrig@vishia.de 335 */ 336 public static final String sVersion = "2016-09-02"; 337 338 339 /**The widget manager from where the widget is organized. Most of methods need the information 340 * stored in the panel manager. This reference is used to set values to other widgets. */ 341 protected GralMng itsMng; 342 343 /**The position of the widget. It may be null if the widget should not be resized. */ 344 private GralPos _wdgPos; 345 346 347 /**The implementation specific widget. The instance is derived from the graphic implementation-specific 348 * super class of all widgets such as {@link org.eclipse.swt.widgets.Control} or {@link java.awt.Component}. 349 * The user can check and cast this instance if some special operations may be need graphic-implementation-dependent. 350 * It is recommended that implementation specific features should not used if they are not necessary 351 * and the application should be held graphic implementation independent. 352 * <br><br> 353 * This reference is null if the GralWidgets extends the Graphic specific implementation widget. 354 * It should be used in the future (2013-06). 355 */ 356 public ImplAccess _wdgImpl; 357 358 359 protected GralMngBuild_ifc buildMng; 360 361 /**Association to the configuration element from where this widget was built. 362 * If the widget is moved or its properties are changed in the 'design mode' of the GUI, 363 * this aggregate data are adjusted and re-written to a file. The configuration elemenet 364 * contains all data which are necessary to build the appearance of the GUI. 365 * <br> 366 * If this aggregation is null, the widget can't be changed in the design mode of the GUI. 367 * It is created directly without configuration data. 368 */ 369 private GralWidgetCfg_ifc itsCfgElement; 370 371 372 373 protected static class ActionChangeSelect 374 { 375 ActionChange onAnyChangeContent; 376 ActionChange onEnter; 377 ActionChange onCtrlEnter; 378 ActionChange onFocusGained; 379 ActionChange onChangeAndFocusLost; 380 ActionChange onMouse1Dn; 381 ActionChange onMouse1Up; 382 ActionChange onMouse1UpOutside; 383 ActionChange onMouse2Up; 384 ActionChange onMouse1Double; 385 ActionChange onMouseWheel; 386 ActionChange onDrop; 387 ActionChange onDrag; 388 389 } 390 391 392 393 394 395 396 397 /**This class holds common configuration data for widgets. 398 */ 399 public final static class ConfigData 400 { 401 /**Action method for showing. */ 402 protected GralUserAction actionShow; 403 404 /**Textual description of the showing method. */ 405 private String sShowMethod; 406 407 private String[] sShowParam; 408 409 410 /**Either this or {@link #actionChangeSelect} is set. */ 411 protected ActionChange actionChange1; 412 413 protected ActionChangeWhen[] actionChange1When; 414 415 /**Either this or {@link #actionChange} is set. */ 416 protected ActionChangeSelect actionChangeSelect; 417 418 /**Action method on activating, changing or release the widget-focus. */ 419 //public GralUserAction actionChanging; 420 421 /**Parameter to the change action. */ 422 //public String[] sActionChangeArgs; 423 424 425 protected GralUserAction actionDrag; 426 427 protected GralUserAction actionDrop; 428 429 /**This action will be called if the widget gets the focus. */ 430 protected GralUserAction actionFocused; 431 432 /**Parameter which are used from a {@link GralWidget#setActionShow(GralUserAction, String[])} method. 433 * The parameter are converted from a String given form. 434 */ 435 public Object[] showParam; 436 437 /**A standard action for a specific widget for example button, which is executed 438 * independently and additional to the user action. */ 439 public GralMouseWidgetAction_ifc mouseWidgetAction; 440 441 442 /**Bits see {@link GralMouseWidgetAction_ifc#mUser1down} etc. */ 443 public int mMouseToActionChange; 444 445 446 } 447 448 /**Reference to the common configuration data for widgets. */ 449 public ConfigData cfg = new ConfigData(); 450 451 /**Name of the widget in the panel. */ 452 public String name; 453 454 455 456 457 /**Panel where the widget is member of. */ 458 //public final GralPanelContent itsPanel; 459 460 /**The graphical widget. It is untyped because it depends on the underlying graphic system. 461 * It may be a wrapper class arround a graphical widget too. 462 * This element is used for setting operations, which depends from the graphic system 463 * and the type of the widget. It is only used in the graphic-system-special implementation. 464 * */ 465 //protected GralWidget_ifc widget; 466 467 /**numeric info what to do (kind of widget). 468 * <ul> 469 * <li>B: a Button: has a color, has an action method. 470 * <li>c: curve view 471 * <li>C: traCk of curve view 472 * <li>D: a LED 473 * <li>xxx E: an edit field, 1 line 474 * <li>xxx e: an edit area 475 * <li>F: input file selection field 476 * <li>f: GralFileSelector 477 * <li>h; HTML text box (browser) 478 * <li>I: a line 479 * <li>i: an image 480 * <li>k: a tree node 481 * <li>K: a tree leafe 482 * <li>l: a list or table 483 * <li>L: a list or table line 484 * <li>M: a Menu entry 485 * <li>n: a Horizontal Selector 486 * <li>r: a rectangle area 487 * <li>P: a plot or canvas area 488 * <li>R: a rectangle line 489 * <li>S: a text field to show 490 * <li>s: a text area. 491 * <li>T: a text input field 492 * <li>t: a text input area. 493 * <li>U: a graphical value representation (bar etc) 494 * <li>V: a graphical value enter representation (slider etc) 495 * <li>w: A window. 496 * <li>@: A Tabbed Panel 497 * <li>$: Any Panel (composite) 498 * <li>+: A canvas panel 499 * <li>*: A type (not a widget, common information) See {@link org.vishia.gral.cfg.GralCfgData#new_Type()} 500 * </ul> 501 * */ 502 public final char whatIs; 503 504 public String sToolTip; 505 506 /**Textual informations about content. It may be a data path or adequate. */ 507 private String sDataPath; 508 509 /**If not null, it is the right-mouse-button menu for this widget. */ 510 protected GralMenu contextMenu; 511 512 513 /**An index associated to the data. */ 514 private int dataIx; 515 516 517 /**Textual info about representation format. 518 * See usage in {@link GralTextField}. 519 * */ 520 protected String sFormat; 521 522 /**Numeric informations about the content. */ 523 //int[] indices; 524 525 /**One variable which is associated with this widget. This reference may be null. 526 * Alternatively {@link #variables} may be set. 527 * See {@link #getVariableFromContentInfo(VariableContainer_ifc)}. 528 * See {@link #setValue(float)}, {@link #setValue(String)}. 529 * See {@link #indices} to use an array- or bit-variable. 530 */ 531 private VariableAccess_ifc variable; 532 533 /**More as one variable which are associated with this widget. This reference may be null. 534 * Alternatively {@link #variable} may be set. 535 * See {@link #getVariableFromContentInfo(VariableContainer_ifc)}. 536 * See {@link #setValue(float)}, {@link #setValue(String)}. 537 * See {@link #indices} to use an array- or bit-variable. 538 */ 539 private List<VariableAccess_ifc> variables; 540 541 542 /**Any widget can have a command String, which can be quest for example in an action. 543 * The widget can be identified by its {@link #getCmd()} independent of its name. */ 544 public String sCmd; 545 546 547 /**The relative path to a html help label (maybe an URL, or file, or file with label). */ 548 protected String htmlHelp; 549 550 /**Any special info, may be set from any user class. It should help to present the content. 551 * This info can be set and changed after registration. */ 552 private Object oContentInfo; 553 554 555 556 557 /**Set true if its shell, tab card etc is be activated. Set false if it is deactivated. 558 * It is an estimation whether this widget is be shown yet. 559 */ 560 protected boolean bVisibleState = true; 561 562 563 /**Set to true on {@link #setEditable(boolean)}. 564 * With that designation the cyclically refresh of the text field can be prevented. 565 * */ 566 protected boolean bEditable; 567 568 569 /**Set on focus gained, false on focus lost. */ 570 protected boolean bHasFocus; 571 572 /**If this bit is true on an edit field, it should be initialized. 573 * 574 */ 575 protected boolean bShouldInitialize = true; 576 577 578 /**Standard delay to repaint if {@link #repaint()} is called without arguments. 579 * It delays a few time because an additional process can be occure in a short time, and only one repaint should be invoked. 580 * The repaintDelayMax limits a shifting to the future. See {@link org.vishia.event.EventTimeout}, that is used. 581 * 582 */ 583 protected int repaintDelay = 30, repaintDelayMax = 100; 584 585 /**The time when the bVisible state was changed. */ 586 long lastTimeSetVisible = 0; 587 588 protected long dateUser; 589 590 /**This inner class holds the dynamic data of a widget. 591 * This data are existent for any widget independent of its type. 592 * It can be used in a specific way depending on the widget type. 593 */ 594 public final static class DynamicData { 595 596 /**32 bit what is changed, see {@link GralWidget#chgColorText} etc. 597 * TODO should be protected. */ 598 private AtomicInteger whatIsChanged = new AtomicInteger(); 599 600 /**Sets what is changed, Bits defined in {@link GralWidget.ImplAccess#chgColorBack} etc. 601 * @param mask one bit or some bits. ImplAccess.chgXYZ 602 */ 603 public void setChanged(int mask){ 604 int catastrophicalCount = 1000; 605 boolean bOk; 606 do { 607 int act =whatIsChanged.get(); 608 int newValue = act | mask; 609 bOk = whatIsChanged.compareAndSet(act, newValue); 610 } while(!bOk && --catastrophicalCount >= 0); 611 } 612 613 614 /**Returns the bits what is changed. 615 * All bits which were evaluated should be acknowledged via {@link #acknChanged(int)} 616 * @return 617 */ 618 public int getChanged(){ return whatIsChanged.get(); } 619 620 /**Resets what is changed, Bits defined in {@link GralWidget.ImplAccess#chgColorBack} etc. 621 * This routine should be called in the paint routine whenever the change was succeeded. 622 * @param mask one bit or some bits. ImplAccess.chgXYZ 623 */ 624 public void acknChanged(int mask){ 625 int catastrophicalCount = 1000; 626 boolean bOk; 627 do { 628 int act =whatIsChanged.get(); 629 int newValue = act & ~mask; 630 bOk = whatIsChanged.compareAndSet(act, newValue); 631 } while(!bOk && --catastrophicalCount >= 0); 632 } 633 634 635 /**Three colors for background, line and text should be convert to the platforms color and used in the paint routine. 636 * If this elements are null, the standard color should be used. */ 637 public GralColor backColor = GralColor.getColor("wh"), backColorNoFocus = GralColor.getColor("lgr") 638 , lineColor = GralColor.getColor("bk"), textColor = GralColor.getColor("bk"); 639 640 /**It depends of the pixel size. Therefore set after setToPanel, if GralMng is known. */ 641 public GralFont textFont; 642 643 /**A text to display. */ 644 public String displayedText; 645 646 /**Any specific value. */ 647 public Object[] oValues; 648 649 public float fValue, minValue, maxValue; 650 651 /**If a long or int value is given, it is stored here. */ 652 public long lValue; 653 654 public Object visibleInfo; 655 656 public Object userData; 657 658 public float[] fValues; 659 660 /**Set to true from any listener of the implementation level if the cursor in the widget is moved or such GUI handling. 661 * Then the content won't be overridden by {@link #setText(CharSequence)} furthermore till the focus is left. 662 */ 663 protected boolean bTouchedField; 664 665 /**Set to true from any listener of the implementation level if the data of the widget was changed from GUI handling. 666 * If the data are changed from any Gral method invocation, this bit should not set to true. 667 * For example a key listener changes the content of a text edit field, then this bit should be set. 668 * This bit should be cleared if the GUI-content of the widget is synchronized with the widget data cells. 669 * Note that the GUI-content of a widget can be changed only in the GUI thread, whereby the content of the 670 * {@link #dyda} can be read and write in any threat. This bit helps to synchronize. */ 671 protected boolean bTextChanged; 672 } 673 674 675 protected final DynamicData dyda = new DynamicData(); 676 677 678 //protected GralWidget(char whatIs) 679 //{ this.whatIs = whatIs; 680 //} 681 682 /**Creates a widget. 683 * @param posString If null then the widget is not positioned. !=null then a position string. 684 * The position is taken relative to the {@link GralMng#pos}, the {@link GralMng#pos} is changed 685 * see {@link GralPos#setPosition(CharSequence, GralPos)} 686 * @param sName If posString is null and sName has the form "@pos = name" then this is a combination from name and pos. 687 * The name should be unified to indent a widget by its name. 688 * @param whatIs 689 * @throws ParseException 690 * @deprecated since 2016-09: The idea is: Use always one String for "@pos=name". 691 */ 692 @Deprecated public GralWidget(String pos, String name, char whatIs){ 693 this(pos !=null ? ( (pos.startsWith("@") ? "" : "@") + pos + "=" + name) : name, whatIs); 694 } 695 696 697 698 /**Creates a widget. 699 * @param sName has the form "@pos = name" then this is a combination from position string and name. 700 * The name should be unified to indent a widget by its name. 701 * Syntax of pos: see {@link GralPos#setPosition(CharSequence, GralPos)}. It is the same syntax as in textual config scripts. 702 * @param whatIs See {@link #whatIs} 703 */ 704 public GralWidget(String sPosName, char whatIs){ 705 int posName; 706 String posString1; 707 if(sPosName !=null && sPosName.startsWith("@") && (posName= sPosName.indexOf('='))>0) { 708 posString1 = sPosName.substring(0, posName).trim(); 709 this.name = sPosName.substring(posName+1).trim(); 710 } else { 711 this.name = sPosName; 712 posString1 = null; 713 } 714 //this.widget = null; 715 this.whatIs = whatIs; 716 //bVisibleState = whatIs != 'w'; //true for all widgets, false for another Windows. 717 bVisibleState = false; //kkkk initially false for all widgets, it will be set true on set focus. For tabbed panels it should be false for the inactive panel. 718 this.itsCfgElement = null; 719 itsMng = GralMng.get(); 720 assert(itsMng !=null); //should be created firstly in the application, since 2015-01-18 721 if(posString1 !=null) { 722 try{ 723 if(whatIs == 'w') { 724 //a window: don't change the GralMng.pos, create a new one. 725 GralPos pos = new GralPos(); 726 pos.panel = itsMng.getPrimaryWindow(); 727 this._wdgPos = pos.setNextPos(posString1); 728 } else { 729 //a normal widget on a panel 730 this._wdgPos = itsMng.pos().pos.setNextPos(posString1); 731 } 732 registerWidget(); 733 } catch(ParseException exc) { 734 throw new IllegalArgumentException("GralWidget - position is syntactical faulty; " + posString1); 735 } 736 } //else: don't set the pos, it is done later 737 } 738 739 740 void registerWidget() { 741 if(this._wdgPos.panel == this) { 742 //don't register the panel itself! 743 } else if(_wdgPos.panel !=null){ 744 this._wdgPos.panel.addWidget(this, _wdgPos.toResize()); 745 } else { 746 this._wdgPos.panel = itsMng.getCurrentPanel(); 747 System.out.println("GralWidget.GralWidget - pos without panel"); 748 } 749 } 750 751 752 @Deprecated public GralWidget(String sName, char whatIs, GralMng mng) 753 { this(sName, whatIs); 754 itsMng = GralMng.get(); 755 assert(itsMng !=null); //should be created firstly in the application, since 2015-01-18 756 if(mng !=null){ 757 assert(this.itsMng == mng); 758 //sets the mng and the pos of Window in that cases 759 //where the mng is present on ctor. (not in new form) 760 //setPanelMng(mng); 761 /* 762 if(mng.posUsed){ 763 mng.pos.setNextPosition(); 764 mng.posUsed = false; 765 } 766 this.pos = mng.getPositionInPanel(); //Note: makes a clone because the pos in panel is reused. 767 */ 768 } 769 } 770 771 772 773 /**Standard implementation of @see org.vishia.gral.ifc.GralWidget_ifc#setToPanel() 774 * Only large widgets (contains more as one GralWidget) should override this method. 775 * If the _wdgImpl is initialized already, this method does nothing. It is possible to invoke this for all existing widgets 776 * of a panel, only new widgets are initialized with them. 777 * @before 2016-07 it has thrown an exception on repeated invocation. 778 */ 779 @Override public void createImplWidget_Gthread() throws IllegalStateException { 780 if(_wdgImpl ==null){ // throw new IllegalStateException("setToPanel faulty call - GralTable;"); 781 GralMng mngg = GralMng.get(); //The implementation should be instantiated already! 782 if(dyda.textFont == null) { //maybe set with knowledge of the GralMng before. 783 dyda.textFont = mngg.propertiesGui.getTextFont(mngg.pos().pos.height()); 784 dyda.setChanged(ImplAccess.chgFont); 785 } 786 mngg.createImplWidget_Gthread(this); 787 } 788 } 789 790 791 792 /** 793 * @see org.vishia.gral.ifc.GralWidget_ifc#setToPanel(org.vishia.gral.ifc.GralMngBuild_ifc) 794 * @deprecated use {@link #createImplWidget_Gthread()} 795 */ 796 @Override @Deprecated public final void setToPanel(GralMngBuild_ifc mngUnused) throws IllegalStateException { createImplWidget_Gthread(); } 797 798 799 public GralPos pos(){ return _wdgPos; } 800 801 802 803 public void chgPos(GralPos newPos){ 804 dyda.setChanged(ImplAccess.chgPos); 805 _wdgPos = newPos; 806 } 807 808 /**Returns this. 809 * @see org.vishia.gral.base.GetGralWidget_ifc#getGralWidget() 810 */ 811 @Override public GralWidget getGralWidget(){ return this; } 812 813 814 /**Default implementation:Most of widgets may have only one implementation widget. This returns null. 815 * @see org.vishia.gral.ifc.GralWidget_ifc#getWidgetMultiImplementations() 816 */ 817 //public Object[] getWidgetMultiImplementations(){ return null; } 818 819 820 821 public void setPrimaryWidgetOfPanel(){ 822 _wdgPos.panel.setPrimaryWidget(this); 823 } 824 825 826 @Override public String getName(){ 827 if(name !=null) return name; 828 else if(sDataPath !=null) return sDataPath; 829 else if(sCmd !=null) return sCmd; 830 else return toString(); 831 } 832 833 /**Sets the graphical widget. It is a wrapper around the widget of the graphic implementation base. 834 * This method shouldn't invoke by an user's application. It is only invoked by the gral itself. 835 * @param widget The wrapper. 836 */ 837 //public void setGraphicWidgetWrapper(GralWidget_ifc widget){ this.widget = widget; } 838 839 /**Gets the graphical widget. The difference between this class and the graphical widget is: 840 * This class contains unified description data to any kind of widget, where the graphical widget 841 * is a special or simple wrapper around the implementation of the widget in the graphical implementation base. 842 * 843 * @return The gral graphical widget. Note: The type can be instanceof some derived interfaces of the gral. 844 * @deprecated 845 */ 846 //@Deprecated 847 //public GralWidget_ifc getGraphicWidgetWrapper(){ return this; } 848 849 850 /**Sets a application specific info. 851 * It should help to present user data which are associated to this widget. 852 * This info can be set and changed anytime. 853 * @deprecated use {@link #setData(Object)} 854 * */ 855 public void setContentInfo(Object content){ oContentInfo = content;} 856 857 /**Gets the application specific info. See {@link #setContentInfo(Object)}. 858 * @deprecated use {@link #getData()} 859 */ 860 public Object getContentInfo(){ return oContentInfo; } 861 862 863 864 /**Sets a application specific data. 865 * It should help to present user data which are associated to this widget. 866 * This info can be set and changed anytime. */ 867 public void setData(Object data){ oContentInfo = data;} 868 869 /**Gets the application specific info. See {@link #setContentInfo(Object)}. */ 870 public Object getData(){ return oContentInfo; } 871 872 873 874 @Override public void setEditable(boolean editable){ 875 if(bEditable != editable) { 876 bEditable = editable; 877 dyda.setChanged(ImplAccess.chgEditable); 878 repaint(repaintDelay, repaintDelayMax); 879 } 880 } 881 882 @Override public boolean isEditable(){ return bEditable; } 883 884 885 @Override public boolean isNotEditableOrShouldInitialize(){ return !bEditable || bShouldInitialize; } 886 887 /**Sets the data path. It is a String in application context. 888 * @param sDataPath 889 */ 890 @Override public void setDataPath(String sDataPath){ 891 this.sDataPath = sDataPath; 892 variable = null; 893 variables = null; 894 } 895 896 /**Changes the data path 897 * @param sDataPath the new one 898 * @return the last one. 899 */ 900 public String getDataPath(String sDataPath) 901 { String sDataPathLast = this.sDataPath; 902 this.sDataPath = sDataPath; 903 return sDataPathLast; 904 } 905 906 /**Any widget can have a command String, which can be quest for example in an action. 907 * The widget can be identified by this method independent of its name. See {@link #setCmd(String)}. */ 908 public String getCmd(){ return sCmd; } 909 910 911 /**Get the command string from the {@link #setCmd(String)} with choice of an option. 912 * The command string should have the form "base[Option1|Option2|Option3]End" 913 * whereby base and end can be empty. if option is <0 an IndexOutOfBoundsException is thrown. 914 * If option is >= the given number of options, the option part is replaced by "??". 915 * That may be more helpfull to detect errors. 916 * @param option number >=0 917 * @return "baseOptionEnd" 918 */ 919 public String getCmd(int option){ 920 int pos1 = sCmd.indexOf('['); 921 int pos2 = sCmd.indexOf(']', pos1+1); 922 if(pos1 >=0 && pos2 > pos1){ 923 String sBase = sCmd.substring(0, pos1); 924 String sEnd = sCmd.substring(pos2+1); //maybe "" 925 String[] sOptions = sCmd.substring(pos1+1, pos2).split("\\|"); 926 if(option >= sOptions.length){ return sBase + "??" + sEnd; } 927 else{ return sBase + sOptions[option] + sEnd; } 928 } else { 929 return sCmd; 930 } 931 } 932 933 /**Any widget can have a command String, which can be quest for example in an action. 934 * The widget can be identified by its {@link #getCmd()} independent of its name which can be set on runtime with this method. */ 935 @Override public void setCmd(String cmd){ sCmd = cmd; } 936 937 938 /**Gets the data path. It is a String in application context. 939 */ 940 @Override public String getDataPath(){ return sDataPath; } 941 942 /**Sets the action in application context for processing of user handling for the widget. 943 * Handling means, pressing button, user inputs of text fields 944 * The method {@link GralUserAction#exec(int, GralWidget_ifc, Object...)} will be called with following key codes: 945 * <ul> 946 * <li>{@link KeyCode#focusGained}, {@link KeyCode#focusLost} on enter and leave a text field. 947 * <li>{@link KeyCode#mouse1Down} etc, any mouse events on any widget. 948 * <li>{@link KeyCode#valueChanged} if the content of a text field is changed. 949 * <li>Some more TODO, set breakpoint in the routine. 950 * </ul> 951 * @param action any instance. Its action method is invoked depending of the type of widget 952 * usual if the user takes an action on screen, press button etc. 953 * 954 */ 955 @Deprecated public void setActionChange(GralUserAction action){ specifyActionChange(null, action, null); } //cfg.actionChanging = action; } 956 957 958 private static ActionChangeWhen[] whenAll = 959 { ActionChangeWhen.onAnyChgContent 960 , ActionChangeWhen.onFocusGained 961 , ActionChangeWhen.onChangeAndFocusLost 962 , ActionChangeWhen.onCtrlEnter 963 , ActionChangeWhen.onDrag 964 , ActionChangeWhen.onDrop 965 , ActionChangeWhen.onEnter 966 , ActionChangeWhen.onMouse1Double 967 , ActionChangeWhen.onMouse1Dn 968 , ActionChangeWhen.onMouse1Up 969 , ActionChangeWhen.onMouse1UpOutside 970 , ActionChangeWhen.onMouse2Up 971 , ActionChangeWhen.onMouseWheel 972 }; 973 974 975 /**Sets the action to invoke after changing or touching the widget. 976 * @param sAction maybe null, String for visualization, especially menu entry for context menu. 977 * @param action The action. null admissible to remove the existing action. 978 * @param args possible arguments for the action or null 979 * @param when List of type of action, maybe empty, then the given action is set for all conditions. 980 * Especially <code>setActionChange(null, null, null) removes all actions. 981 */ 982 public void specifyActionChange(String sAction, GralUserAction action, String[] args, ActionChangeWhen... when){ 983 ActionChange action1 = action == null ? null : new ActionChange(sAction, action, args); 984 985 if(when.length==0){ 986 cfg.actionChange1 = action1; 987 cfg.actionChangeSelect = null; 988 cfg.actionChange1When = null; 989 } else if(cfg.actionChange1 == null && cfg.actionChangeSelect == null) { 990 //first invocation, only one action but for special operations (when) 991 cfg.actionChange1 = action1; 992 cfg.actionChangeSelect = null; 993 cfg.actionChange1When = when; 994 } else { 995 if(cfg.actionChangeSelect == null) { cfg.actionChangeSelect = new ActionChangeSelect(); } 996 if(cfg.actionChange1 !=null) { //given 997 ActionChangeWhen[] whenGiven = cfg.actionChange1When == null ? whenAll : cfg.actionChange1When; 998 for(ActionChangeWhen when1: whenGiven) { 999 specifyActionChangeWhen(cfg.actionChange1, when1); 1000 } 1001 cfg.actionChange1 = null; 1002 } 1003 for(ActionChangeWhen when1: when) { 1004 specifyActionChangeWhen(action1, when1); 1005 } 1006 } 1007 } 1008 1009 1010 private void specifyActionChangeWhen(ActionChange action, ActionChangeWhen when) 1011 { 1012 switch(when){ 1013 case onAnyChgContent: cfg.actionChangeSelect.onAnyChangeContent = action; break; 1014 case onCtrlEnter: cfg.actionChangeSelect.onCtrlEnter = action; break; 1015 case onFocusGained: cfg.actionChangeSelect.onFocusGained = action; break; 1016 case onChangeAndFocusLost: cfg.actionChangeSelect.onChangeAndFocusLost = action; break; 1017 case onDrag: cfg.actionChangeSelect.onDrag = action; break; 1018 case onDrop:cfg.actionChangeSelect.onDrop = action; break; 1019 case onEnter: cfg.actionChangeSelect.onEnter = action; break; 1020 case onMouse1Double: cfg.actionChangeSelect.onMouse1Double = action; break; 1021 case onMouse1Dn: cfg.actionChangeSelect.onMouse1Dn = action; break; 1022 case onMouse1Up: cfg.actionChangeSelect.onMouse1Up = action; break; 1023 case onMouse1UpOutside: cfg.actionChangeSelect.onMouse1UpOutside = action; break; 1024 case onMouse2Up: cfg.actionChangeSelect.onMouse2Up = action; break; 1025 case onMouseWheel: cfg.actionChangeSelect.onMouseWheel = action; break; 1026 default: throw new IllegalArgumentException("not all when-conditions"); 1027 } 1028 } 1029 1030 1031 1032 public void specifyContextMenu(GralMenu menu) { 1033 if(_wdgImpl !=null && _wdgImpl.wdgimpl !=null) { _wdgImpl.wdgimpl.specifyContextMenu(menu); } 1034 else { } //TODO set to instanciation data 1035 1036 } 1037 1038 1039 1040 1041 /**Gets the action to execute on changing a widget. 1042 * If only one action is given with <code>setActionChange(String, action, args) without a specified when then this action is returned in any case, 1043 * especially if when == null. If specific actions were set, this action is returned, or null. 1044 * @param when type of action, if null then returns the only one given action or null if only specific actions are given 1045 * @return null if the action is not set. 1046 */ 1047 @Override public ActionChange getActionChange(ActionChangeWhen when) { 1048 return getActionChangeStrict(when, false); 1049 } 1050 1051 1052 /**Gets the action to execute on changing a widget. 1053 * If only one action is given with <code>setActionChange(String, action, args) without a specified when then this action is returned in any case, 1054 * especially if when == null. If specific actions were set, this action is returned, or null. 1055 * @param when type of action, if null then returns the only one given action or null if only specific actions are given 1056 * @param strict if true then a common action without when-designation is not returned if when is not null. 1057 * @return null if the action is not set. 1058 */ 1059 public ActionChange getActionChangeStrict(ActionChangeWhen when, boolean strict) { 1060 if(cfg.actionChange1 !=null) { 1061 if(cfg.actionChange1When == null){ 1062 return strict && when !=null 1063 ? null //specific action required and strict: returns null though a common action is given. 1064 : cfg.actionChange1; //no specific action required or set, or no specifia action set and not strict: returns the only one action. 1065 } else { 1066 for(ActionChangeWhen when1:cfg.actionChange1When){ 1067 if(when1 == when) return cfg.actionChange1; 1068 } 1069 //not found: 1070 return null; 1071 } 1072 } else { 1073 //actionChangeSelect is given: 1074 if(when == null || cfg.actionChangeSelect == null) return null; 1075 switch(when){ 1076 case onAnyChgContent: return cfg.actionChangeSelect.onAnyChangeContent; 1077 case onCtrlEnter: return cfg.actionChangeSelect.onCtrlEnter; 1078 case onFocusGained: return cfg.actionChangeSelect.onFocusGained; 1079 case onChangeAndFocusLost: return cfg.actionChangeSelect.onChangeAndFocusLost; 1080 case onDrag: return cfg.actionChangeSelect.onDrag; 1081 case onDrop: return cfg.actionChangeSelect.onDrop; 1082 case onEnter: return cfg.actionChangeSelect.onEnter; 1083 case onMouse1Double: return cfg.actionChangeSelect.onMouse1Double; 1084 case onMouse1Dn: return cfg.actionChangeSelect.onMouse1Dn; 1085 case onMouse1Up: return cfg.actionChangeSelect.onMouse1Up; 1086 case onMouse1UpOutside: return cfg.actionChangeSelect.onMouse1UpOutside; 1087 case onMouse2Up: return cfg.actionChangeSelect.onMouse2Up; 1088 case onMouseWheel: return cfg.actionChangeSelect.onMouseWheel; 1089 default: throw new IllegalArgumentException("not all when-conditions"); 1090 } 1091 } 1092 } 1093 1094 1095 1096 1097 1098 1099 /**Sets the action for mouse operation. Either it is a special mouse handler or the {@link #setActionChange(GralUserAction)} 1100 * is used with {@link KeyCode#mouse1Down} etc. key code. 1101 * It works with all widgets which uses {@link org.vishia.gral.swt.SwtGralMouseListener.MouseListenerGralAction} respectively the adequate implementation mouse listener. 1102 * By contract of Gral, all widgets should add the mouse listener. Therefore no further special action is necessary to activate the requested mouse behavior. 1103 * Note: If you set an abbreviate mouse handler for Button etc. where the mouse is an essential functionality 1104 * that functionality is disturbed. An extra handler should base on that special mouse handler, for example 1105 * {@link GralButton.MouseActionButton} and should invoke that actions calling super.mouse1Down(...) etc. 1106 * For that widgets usual the {@link #setActionChange(GralUserAction)} is called also, that may be sufficient. 1107 * @param mouseWidgetAction null possible, elsewhere the mouse operation callback instance. 1108 * @param mUser One or more of the bits {@link GralMouseWidgetAction_ifc#mUser1down} etc. 1109 * If given the {@link #setActionChange(GralUserAction)} is invoked with that operation instead the given (or usually not given) mouseWidgetAction. 1110 */ 1111 public void setActionMouse(GralMouseWidgetAction_ifc mouseWidgetAction, int mUser){ 1112 cfg.mouseWidgetAction = mouseWidgetAction; 1113 cfg.mMouseToActionChange = mUser; 1114 } 1115 1116 1117 1118 1119 /**Gets the action for change the widget. */ 1120 //public GralUserAction getActionChange(){ return cfg.actionChanging; } 1121 1122 1123 /**Sets the action in application context which is invoked for applying user data to show in the widget. 1124 * <br><br> 1125 * The invocation of the action should be organized in the user context, maybe cyclically for all widgets 1126 * of visible windows or if any data are received. 1127 * <br><br> 1128 * In the action the user should read any data from its application 1129 * and invoke {@link #setValue(int, int, Object, Object)} after data preparation to display the value. 1130 * Because the {@link GralWidget} is given as parameter, the implementation can use the information 1131 * for example {@link #sDataPath} or {@link #sFormat}. The implementation of the action can be done 1132 * in the users context in a specialized form, or some standard actions can be used. 1133 * See notes of {@link #getActionShow()}. 1134 * <br><br> 1135 * To get the action in a script context (GuiCfgBuilder) some actions can be registered 1136 * using {@link org.vishia.gral.ifc.GralMngBuild_ifc#registerUserAction(String, GralUserAction)}. They are gotten by name 1137 * invoking {@link org.vishia.gral.ifc.GralMngBuild_ifc#getRegisteredUserAction(String)} 1138 * in the {@link org.vishia.gral.cfg.GralCfgBuilder}. 1139 * 1140 * @param action The action instance. 1141 * @param param maybe param for the show method. 1142 */ 1143 public void setActionShow(GralUserAction action, String[] param){ cfg.actionShow = action; cfg.sShowParam = param; } 1144 1145 /**Gets the action to show the widget. This method is helpfully to invoke showing after receiving data 1146 * in the users context. Invoke {@link GralUserAction#userActionGui(String, GralWidget, Object...)} 1147 * with this WidgetDescriptor and additional user data. The implementation of that method 1148 * may be done in the users context but in another module or the implementation may be given in any 1149 * library superordinated to this graphic adapter library but subordinated in respect to the explicit application. 1150 * The usage of a show method given in the implementation of {@link GralUserAction} helps to separate 1151 * the invocation of showing and the decision what and how is to show. 1152 */ 1153 public GralUserAction getActionShow(){ return cfg.actionShow; } 1154 1155 public void setActionFocused(GralUserAction action){ cfg.actionFocused = action; } 1156 1157 public GralUserAction getActionFocused(){ return cfg.actionFocused; } 1158 1159 1160 public String getsToolTip() 1161 { 1162 return sToolTip; 1163 } 1164 1165 1166 public void setToolTip(String sToolTip) 1167 { 1168 this.sToolTip = sToolTip; 1169 } 1170 1171 1172 /**Sets the action to receive a drop event and initializes the drop feature of the widget. 1173 * For drag file the 'drag get action' method will be offered in the params[0] a String[][] reference. 1174 * This String reference array has to be filled with the absolute path of the file using String[0][0]. 1175 * After that callback invocation a drag file object will be created therewith internally. 1176 * 1177 * @param action The drag file get action. 1178 * @param dropType one of {@link org.vishia.util.KeyCode#dropFiles} or ..dropText 1179 */ 1180 public void setDragEnable(GralUserAction action, int dragType) 1181 { 1182 cfg.actionDrag = action; 1183 if(_wdgImpl !=null) _wdgImpl.setDragEnable(dragType); // call implementation specific drop handling. 1184 } 1185 1186 public GralUserAction getActionDrag(){ return cfg.actionDrag; } 1187 1188 1189 /**Sets the action to receive a drop event and initializes the drop feature of the widget. 1190 * @param action The action will be called 1191 * @param dropType one of {@link org.vishia.util.KeyCode#dropFiles} or ..dropText 1192 */ 1193 public void setDropEnable(GralUserAction action, int dropType) 1194 { 1195 cfg.actionDrop = action; 1196 if(_wdgImpl !=null) _wdgImpl.setDropEnable(dropType); // call implementation specific drop handling. 1197 } 1198 1199 public GralUserAction getActionDrop(){ return cfg.actionDrop; } 1200 1201 1202 public String getShowMethod() 1203 { 1204 return cfg.sShowMethod; 1205 } 1206 1207 1208 public int getDataIx(){ return dataIx; } 1209 1210 public void setDataIx(int dataIx){ this.dataIx = dataIx; } 1211 1212 1213 /**Returns the parameter of the show method. 1214 * The parameters for the show-method are given as "showMethod(param, param, ...)" 1215 * while calling {@link #setActionShow(GralUserAction, String[])}. They are split in extra Strings, 1216 * this 1217 * @return 1218 */ 1219 public String[] getShowParam(){ return cfg.sShowParam; } 1220 1221 /**Clear the parameter if they are over-taken already. 1222 */ 1223 public void clearShowParam(){ cfg.sShowParam = null; } 1224 1225 1226 public String getFormat() 1227 { 1228 return sFormat; 1229 } 1230 1231 1232 public void setFormat(String sFormat) 1233 { 1234 this.sFormat = sFormat; 1235 } 1236 1237 1238 /**Gets the context menu to add a menu item. If this widget hasn't a gral context menu, then 1239 * the context menu is created by calling {@link GralMng#addContextMenu(GralWidget)}. 1240 * If the widget has a context menu already, it is stored in the reference {@link #contextMenu}. 1241 * @return the context menu root for this widget. 1242 */ 1243 public GralMenu getContextMenu(){ 1244 if(contextMenu == null){ 1245 contextMenu = itsMng.createContextMenu(this); //delegation, the widget mng knows the implementation platform. 1246 } 1247 return contextMenu; 1248 } 1249 1250 1251 public void setHtmlHelp(String url){ htmlHelp = url; } 1252 1253 public String getHtmlHelp(){ return htmlHelp; } 1254 1255 1256 1257 1258 /**Sets the GralMng. 1259 * @deprecated it should be set by the MethodsCalledbackFromImplementation ctor. 1260 */ 1261 @Deprecated 1262 public void setPanelMng(GralMng mng) 1263 { this.itsMng = mng; 1264 if(this._wdgPos !=null) 1265 throw new IllegalStateException("GralWidget - setPos() is set already."); 1266 this._wdgPos = mng.getPosCheckNext(); 1267 this.registerWidget(); //always clone it from the central pos 1268 1269 } 1270 1271 1272 1273 /**Gets the info to access the values for this widget in the users context. 1274 * If this method is called the first time for the widget after start the application, the access info 1275 * is searched in the container calling {@link VariableContainer_ifc#getVariable(String, int[])} 1276 * with the stored textual info {@link #setDataPath(String)} and {@link #setDataIx(int)}. 1277 * This operation may need a little bit of calculation time, which were to expensive if a lot of widgets 1278 * should be provided with user values. Therefore the returned {@link VariableAccess_ifc} instance is stored 1279 * in the {@link #oContentInfo} of the widget and returned on the further calls. 1280 * <br> 1281 * The returned {@link VariableAccess_ifc} should be allow the fast access to users values. 1282 * 1283 * @param container The container where all {@link VariableAccess_ifc} should be found. 1284 * @return The access to a user variable in the user's context, null if the data path is empty. 1285 */ 1286 @Deprecated public VariableAccess_ifc getVariableFromContentInfo(VariableContainer_ifc container) 1287 { 1288 //DBbyteMap.Variable variable; 1289 VariableAccess_ifc variable; 1290 Object oContentInfo = this.getContentInfo(); 1291 if(oContentInfo == null){ 1292 //first usage: 1293 String sPath1 = this.getDataPath(); 1294 if(sPath1 !=null && (sPath1 = sPath1.trim()).length()>0){ 1295 String sPath = itsMng.getReplacerAlias().replaceDataPathPrefix(sPath1); 1296 variable = container.getVariable(sPath1); 1297 this.setContentInfo(variable); 1298 } else { 1299 variable = null; 1300 } 1301 } else if(oContentInfo instanceof VariableAccessWithIdx){ 1302 variable = (VariableAccessWithIdx)oContentInfo; 1303 } else { 1304 variable = null; //other info in widget, not a variable. 1305 } 1306 return variable; 1307 } 1308 1309 1310 1311 public VariableAccess_ifc getVariable(VariableContainer_ifc container) { 1312 1313 if(variable ==null && variables == null && sDataPath !=null && !sDataPath.startsWith("#")){ //no variable known, get it. 1314 if(sDataPath.contains(",")){ 1315 String[] sDataPaths = sDataPath.split(","); 1316 variables = new LinkedList<VariableAccess_ifc>(); 1317 for(String sPath1: sDataPaths){ 1318 if(sPath1.contains("[")) 1319 stop(); 1320 String sPath2 = sPath1.trim(); 1321 String sPath = itsMng.getReplacerAlias().replaceDataPathPrefix(sPath2); 1322 VariableAccess_ifc variable1 = container.getVariable(sPath); 1323 if(variable1 !=null){ 1324 variables.add(variable1); 1325 } 1326 } 1327 } else { 1328 if(sDataPath.contains("[")) 1329 stop(); 1330 String sPath2 = sDataPath.trim(); 1331 String sPath = itsMng.getReplacerAlias().replaceDataPathPrefix(sPath2); 1332 variable = container.getVariable(sPath); 1333 } 1334 } 1335 if(variable !=null) return variable; 1336 if(variables !=null && variables.size() >0) return variables.get(0); 1337 else return null; 1338 } 1339 1340 1341 @Override public void refreshFromVariable(VariableContainer_ifc container){ 1342 refreshFromVariable(container, -1, null, null); 1343 } 1344 1345 1346 1347 1348 1349 1350 /**Refreshes the graphical content with the content of the variables. 1351 * First time if a variables is not associated the variable is searched in the container 1352 * by the given {@link #setDataPath(String)}. The next times the variable is used independent of 1353 * the reference to the container and independent of the data path. If {@link #setDataPath(String)} 1354 * was called again, the variables are searched in the container newly. 1355 * <br><br> 1356 * If the data path contains ',' as separator, more as one variable is associated. 1357 * 1358 * @param container contains variables able to search by string. 1359 */ 1360 @Override public void refreshFromVariable(VariableContainer_ifc container 1361 , long timeLatest, GralColor colorRefreshed, GralColor colorOld 1362 ){ 1363 if(sDataPath !=null && sDataPath.startsWith("intern")) 1364 stop(); 1365 if(this instanceof GralLed) 1366 stop(); 1367 // 1368 if(dyda.bTouchedField) return; //do not modify if it is actually touching. 1369 //check and search the variable(s): 1370 // 1371 getVariable(container); 1372 // 1373 // 1374 // 1375 if(cfg.actionShow !=null){ 1376 //The users method to influence how the widget is presented in view: 1377 if(!cfg.actionShow.exec(0, this, variable !=null ? variable : variables)){ 1378 System.err.println("GralWidget fault actionShow in " + name + "; returns false; sShowMethod = " + cfg.sShowMethod); 1379 } 1380 } else { 1381 //standard behavior to show: call setValue or setText which may overridden by the widget type. 1382 if(variable !=null){ 1383 if(sDataPath !=null && sDataPath.contains("#dEB:activeDamping.i1intg")) 1384 Assert.stop(); 1385 if(colorRefreshed !=null && colorOld !=null){ 1386 long timeVariable = variable.getLastRefreshTime(); 1387 long timediff = timeVariable - timeLatest; 1388 boolean bOld = timeVariable == 0 || timediff < 0; 1389 if(bOld ){ 1390 setBackColor(colorOld, 0); 1391 } else { 1392 setBackColor(colorRefreshed, 0); 1393 } 1394 } 1395 char cType = variable.getType(); 1396 String sValue = null; 1397 switch(cType){ 1398 case 'Z': case 'S': case 'B': 1399 case 'I': setLongValue(variable.getInt()); break; 1400 case 'L': setLongValue(variable.getLong()); break; 1401 case 'F': setValue(variable.getFloat()); break; 1402 case 'D': 1403 Object[] value = new Double[1]; 1404 value[0] = new Double(variable.getDouble()); 1405 setValue(value); 1406 break; 1407 case 's': setText(variable.getString()); break; 1408 default: sValue = "?" + cType; //variable.getInt()); //at least request newly if type is faulty 1409 } 1410 if(sValue !=null){ //if the value is given as sValue-string - if null it may be set already 1411 //if(bOld){ setText("? " + sValue); } 1412 //else 1413 { setText(sValue); } 1414 } 1415 } else if(variables !=null){ 1416 if(variables.size() == 0){ variables = null; } 1417 else { 1418 Object[] values = new Object[variables.size()]; 1419 int ixVal = -1; 1420 for(VariableAccess_ifc variable1: variables){ 1421 char cType = variable1.getType(); 1422 switch(cType){ 1423 case 'Z': case 'S': case 'B': 1424 case 'I': values[++ixVal] = variable1.getInt(); break; 1425 case 'L': setValue(variable.getFloat()); break; 1426 case 'F': values[++ixVal] = variable1.getFloat(); break; 1427 case 's': values[++ixVal] = variable1.getString(); break; 1428 default: setText("?" + cType); //variable.getInt()); //at least request newly 1429 } //switch 1430 1431 } 1432 setValue(values); 1433 } 1434 } else if(sDataPath !=null){ 1435 setText("?? " + sDataPath); //called on fault variable path. 1436 setBackColor(colorOld, 0); 1437 } 1438 } 1439 1440 } 1441 1442 1443 1444 /**Requests new values for all variables which are associated to this widget. This method is usefull 1445 * if the variables are filled by a communication with any remote device and that filling 1446 * should be requested for the current visible variables. 1447 */ 1448 public void requestNewValueForVariable(long timeRequested){ 1449 if(variable !=null){ variable.requestValue(timeRequested); } 1450 else if(variables !=null){ 1451 for(VariableAccess_ifc variable1: variables){ 1452 variable1.requestValue(timeRequested); 1453 } 1454 } 1455 } 1456 1457 1458 1459 /**Gets the current value of the content of the widget in the given context. 1460 * @param mng The context. 1461 * @return The value in String representation, null if the widget has no possibility of input. 1462 */ 1463 public String getValue() 1464 { return itsMng.getValueFromWidget(this); 1465 } 1466 1467 1468 1469 @Override public boolean isVisible(){ 1470 return bVisibleState; 1471 } 1472 1473 1474 @Override public boolean isInFocus(){ 1475 return bHasFocus; 1476 } 1477 1478 1479 @Override public boolean isGraphicDisposed(){ 1480 return lastTimeSetVisible !=0 && _wdgImpl ==null; 1481 } 1482 1483 1484 1485 1486 /**Sets the widget visible or not. It is the default implementation for all simple widgets: 1487 * Sets {@link ImplAccess#chgVisible} or {@link ImplAccess#chgInvisible} in {@link DynamicData#setChanged(int)} 1488 * and invokes {@link #repaint()} with the {@link #repaintDelay} and {@link #repaintDelayMax} 1489 * @param visible 1490 * @return the old state. 1491 */ 1492 @Override public boolean setVisible(boolean visible){ 1493 if(this instanceof GralTable) 1494 System.out.println("GralTable set " + (visible? "visible: " : "invisible: ") + this.name); 1495 if(this instanceof GralWindow) 1496 Debugutil.stop(); 1497 if(_wdgImpl == null) { 1498 bVisibleState = true; //without graphic yet now 1499 } else { 1500 if(itsMng.currThreadIsGraphic()) { 1501 _wdgImpl.setVisibleGThread(visible); //sets the implementation widget visible. 1502 } else { 1503 dyda.setChanged(visible ? ImplAccess.chgVisible : ImplAccess.chgInvisible); 1504 repaint(); 1505 } 1506 } 1507 return bVisibleState; 1508 } 1509 1510 1511 1512 1513 //@Override 1514 public GralRectangle XXXgetPixelPositionSize(){ 1515 if(_wdgImpl !=null) return _wdgImpl.getPixelPositionSize(); 1516 else throw new IllegalArgumentException("GralWidget - does not know its implementation widget; "); 1517 } 1518 1519 1520 @Override public boolean isChanged(boolean setUnchanged){ 1521 boolean bChanged = dyda.bTextChanged; 1522 if(setUnchanged){ 1523 dyda.bTextChanged = false; 1524 } 1525 return bChanged; 1526 } 1527 1528 1529 1530 /**Sets the current value of the content of the widget in the given context. 1531 * @param cmd see {@link GralMng_ifc#cmdSet} etc. It is possible to set the color etc. 1532 * @param ident Any number to specify set, maybe 0 1533 * @param value The value in the necessary representation. 1534 */ 1535 public void setValue(int cmd, int ident, Object visibleInfo) 1536 { dyda.visibleInfo = visibleInfo; 1537 dyda.setChanged(ImplAccess.chgVisibleInfo); 1538 repaint(repaintDelay, repaintDelayMax); 1539 //itsMng.setInfo(this, cmd, ident, visibleInfo, null); 1540 } 1541 1542 1543 @Override public void setBackColor(GralColor color, int ix){ 1544 if(dyda.backColor == null || color.notUsed() || !dyda.backColor.equals(color)){ 1545 dyda.backColor = color; 1546 dyda.setChanged(ImplAccess.chgColorBack); 1547 repaint(repaintDelay, repaintDelayMax); 1548 } 1549 } 1550 1551 @Override public GralColor getBackColor(int ix){ 1552 return dyda.backColor; 1553 } 1554 1555 @Override public void setLineColor(GralColor color, int ix){ 1556 if(dyda.lineColor == null || !dyda.lineColor.equals(color)){ 1557 dyda.lineColor = color; 1558 dyda.setChanged(ImplAccess.chgColorLine); 1559 repaint(repaintDelay, repaintDelayMax); 1560 } 1561 } 1562 1563 @Override public void setTextColor(GralColor color){ 1564 if(dyda.textColor == null || !dyda.textColor.equals(color)){ 1565 dyda.textColor = color; 1566 dyda.setChanged(ImplAccess.chgColorText); 1567 repaint(repaintDelay, repaintDelayMax); 1568 } 1569 } 1570 1571 1572 1573 /**Sets the current value of the content of the widget in the given context. 1574 * @param cmd see {@link GralMng_ifc#cmdSet} etc. It is possible to set the color etc. 1575 * @param ident Any number to specify set, maybe 0 1576 * @param value The value in the necessary representation. 1577 */ 1578 public void setValue(int cmd, int ident, Object visibleInfo, Object userData) 1579 { dyda.visibleInfo = visibleInfo; 1580 dyda.userData = userData; 1581 repaint(repaintDelay, repaintDelayMax); 1582 //itsMng.setInfo(this, cmd, ident, visibleInfo, userData); 1583 } 1584 1585 /**Sets a value to show. 1586 * @param value 1587 * This routine may be overridden by some specialized widgets. 1588 */ 1589 @Override public void setValue(float value){ 1590 dyda.fValue = value; 1591 repaint(repaintDelay, repaintDelayMax); 1592 //itsMng.setInfo(this, GralMng_ifc.cmdSet, 0, value, null); 1593 } 1594 1595 1596 /**Sets a value to show. 1597 * @param value 1598 * This routine may be overridden by some specialized widgets. 1599 */ 1600 @Override public void setLongValue(long value){ 1601 dyda.fValue = value; //may be shorten in acceleration 1602 dyda.lValue = value; 1603 repaint(repaintDelay, repaintDelayMax); 1604 //itsMng.setInfo(this, GralMng_ifc.cmdSet, 0, value, null); 1605 } 1606 1607 1608 1609 /**Gets the float attribute value of this widget. Returns 0.0 if a float value is never used. 1610 */ 1611 public float getFloatValue(){ return dyda.fValue; } 1612 1613 1614 /**Gets the float attribute value of this widget. Returns 0.0 if a float value is never used. 1615 */ 1616 public float getLongValue(){ return dyda.lValue; } 1617 1618 1619 /**Sets some value to show any content. 1620 * @param value 1621 * This routine may be overridden by some specialized widgets. 1622 */ 1623 @Override public void setValue(Object[] value){ 1624 dyda.oValues = value; 1625 repaint(repaintDelay, repaintDelayMax); 1626 //itsMng.setInfo(this, GralMng_ifc.cmdSet, 0, value, null); 1627 } 1628 1629 1630 1631 @Override public void setText(CharSequence text){ 1632 dyda.displayedText = text.toString(); 1633 dyda.setChanged(ImplAccess.chgText); 1634 repaint(repaintDelay, repaintDelayMax); 1635 //System.err.println(Assert.stackInfo("GralWidget - non overridden setText called; Widget = " + name + "; text=" + text, 5)); 1636 } 1637 1638 /**Get the text of this widget. It can be invoked in any thread. 1639 * If it is a edit able text field, it returns the current text after focus lost 1640 * or pressing any control key. 1641 * @return The current text. 1642 */ 1643 public String getText(){ return dyda.displayedText == null? "" : dyda.displayedText; } 1644 1645 1646 /**Sets the border of the value range for showing. 1647 * If it is a ValueBar, for exmaple, it is the value for 0% and 100% 1648 * This routine is empty per default, should be overridden if it is necessary. 1649 * @param minValue 1650 * @param maxValue 1651 */ 1652 @Override public void setMinMax(float minValue, float maxValue){ 1653 dyda.minValue = minValue; 1654 dyda.maxValue = maxValue; 1655 repaint(repaintDelay, repaintDelayMax); 1656 // 1657 } 1658 1659 1660 @Override public long setContentIdent(long date){ long last = dateUser; dateUser = date; return last; } 1661 1662 @Override public long getContentIdent(){ return dateUser; } 1663 1664 1665 1666 1667 public void setCfgElement(GralWidgetCfg_ifc cfge) 1668 { this.itsCfgElement = cfge; 1669 } 1670 1671 1672 public GralWidgetCfg_ifc getCfgElement() 1673 { return itsCfgElement; 1674 } 1675 1676 1677 /**Standard implementation. Override only if necessary for sepcial handling. 1678 * @see org.vishia.gral.ifc.GralWidget_ifc#setFocus() 1679 */ 1680 public void setFocus(){ setFocus(0,0); } 1681 1682 1683 1684 /**Sets the focus to this widget. This method is possible to call in any thread. 1685 * If it is called in the graphic thread and the delay = 0, then it is executed immediately. 1686 * Elsewhere the request is stored in the graphic thread execution queue and invoked later. 1687 * If the widget is inside a tab of a tabbed panel, the tab is designated as currently therewith. 1688 * That is done in the calling thread because it is a thread safe operation. 1689 * 1690 * @param delay Delay in ms for invoking the focus request 1691 * @param latest 1692 */ 1693 public void setFocus(int delay, int latest){ 1694 if(delay >0 || !itsMng.currThreadIsGraphic() || _wdgImpl == null) { 1695 dyda.setChanged(ImplAccess.chgFocus | ImplAccess.chgVisible); 1696 repaint(delay, latest); 1697 } else { 1698 //action in the graphic thread. 1699 if(!bHasFocus) { 1700 GralWidget child = this; 1701 if(! (child instanceof GralWindow)) { 1702 GralPanelContent parent = _wdgPos.panel; 1703 int catastrophicalCount = 100; 1704 //set the visible state and the focus of the parents. 1705 while(parent !=null && parent.pos() !=null //a panel is knwon, it has a parent inside its pos() 1706 && !parent.bHasFocus 1707 && parent._wdgImpl !=null 1708 && --catastrophicalCount >=0){ 1709 parent._wdgImpl.setFocusGThread(); 1710 parent.setVisibleStateWidget(true); 1711 if(parent instanceof GralTabbedPanel) { 1712 //TabbedPanel: The tab where the widget is member of have to be set as active one. 1713 GralTabbedPanel panelTabbed = (GralTabbedPanel)parent; 1714 assert(child instanceof GralPanelContent); 1715 panelTabbed.selectTab(child.name); 1716 //String name = panel1.getName(); 1717 //panelTabbed.selectTab(name); //why with name, use GralPanel inside GralTabbedPanel immediately! 1718 } 1719 if(parent instanceof GralWindow) { //This is not the window itself 1720 parent = null; 1721 } else { 1722 child = parent; 1723 parent = parent.pos().panel; // 1724 } 1725 } 1726 } 1727 _wdgImpl.setFocusGThread(); //sets the focus to the 1728 bVisibleState = true; 1729 } 1730 GralWidget parent = this; 1731 GralWidget child; 1732 GralPanelContent panel; 1733 while(parent instanceof GralPanelContent 1734 && (child = (panel = (GralPanelContent)parent).primaryWidget) !=null 1735 && child._wdgImpl !=null 1736 && !child.bHasFocus 1737 ) { 1738 child.setFocus(); 1739 child._wdgImpl.setFocusGThread(); 1740 child.bVisibleState = true; 1741 child._wdgImpl.repaintGthread(); 1742 List<GralWidget> listWidg = panel.getWidgetList(); 1743 1744 if(!(panel instanceof GralTabbedPanel)) { //don't show all childs of all tabs! 1745 for(GralWidget widgChild : listWidg) { 1746 widgChild._wdgImpl.setVisibleGThread(true); 1747 widgChild.bVisibleState = true; 1748 } 1749 } 1750 parent = child; //loop if more as one GralPanelContent 1751 } 1752 } 1753 } 1754 1755 1756 1757 1758 /**Gets the working interface of the manager. 1759 * It can be used to set and get values from other widgets symbolic identified by its name. 1760 * Note: It is possible too to store the {@link GralWidget} of specific widgets 1761 * to get and set values and properties of this widgets non-symbolic. 1762 * @return The manager. 1763 */ 1764 @Override public GralMng gralMng(){ return itsMng; } 1765 1766 1767 /**Gets the panel where the widget is member of. 1768 * @return The panel. 1769 */ 1770 public GralPanelContent getItsPanel(){ return _wdgPos.panel; } 1771 1772 1773 /* (non-Javadoc) 1774 * @see org.vishia.gral.ifc.GralWidget_ifc#repaint() 1775 */ 1776 @Override public void repaint(){ 1777 //without arguments: latest with repaintDelayMax. 1778 repaint(this.repaintDelay, this.repaintDelayMax); 1779 /*chg 2015-06-25 it is twice and not complete. An order was delayed in the future always. 1780 if(itsMng !=null){ //NOTE: set of changes is possible before setToPanel was called. 1781 if(itsMng.currThreadIsGraphic()){ 1782 repaintGthread(); //do it immediately if no thread switch is necessary. 1783 } else { 1784 repaintRequ.activateAt(System.currentTimeMillis() + repaintDelay); //TODO repaintDelayMax 1785 } 1786 } 1787 */ 1788 } 1789 1790 1791 /**The Implementation of repaint calls {@link #repaintGthread()} if it is the graphic thread and the delay is 0. 1792 * Elsewhere the {@link #repaintRequ} is added as request to the graphic thread. 1793 * @see org.vishia.gral.ifc.GralWidget_ifc#repaint(int, int) 1794 */ 1795 @Override public void repaint(int delay, int latest){ 1796 if(itsMng !=null){ //NOTE: set of changes is possible before setToPanel was called. 1797 if(delay == 0 && itsMng.currThreadIsGraphic() && _wdgImpl !=null){ 1798 _wdgImpl.repaintGthread(); 1799 } else { 1800 long time = System.currentTimeMillis(); 1801 repaintRequ.activateAt(time + delay, time + latest); 1802 } 1803 } 1804 } 1805 1806 1807 1808 /**Removes the widget from the lists in its panel and from the graphical representation. 1809 * It calls the protected {@link #removeWidgetImplementation()} which is implemented in the adaption. 1810 */ 1811 @Override public boolean remove() 1812 { 1813 if(_wdgImpl !=null) _wdgImpl.removeWidgetImplementation(); 1814 if(_wdgPos.panel !=null) { 1815 _wdgPos.panel.removeWidget(this); 1816 } 1817 itsMng.deregisterWidgetName(this); 1818 return true; 1819 } 1820 1821 1822 1823 /**Especially for test and debug, short info about widget. 1824 * @see java.lang.Object#toString() 1825 */ 1826 @Override public String toString() 1827 { StringBuilder u = new StringBuilder(240); 1828 u.append(whatIs).append(":").append(name).append(": ").append(sDataPath); 1829 if(_wdgPos !=null && _wdgPos.panel !=null){ 1830 u.append(" @").append(_wdgPos.panel.name); 1831 } else { 1832 u.append(" @?"); 1833 } 1834 if(variable !=null){ 1835 String vString = variable.toString(); 1836 u.append(" var=").append(vString); 1837 } 1838 //u.append('\n'); 1839 return u.toString(); 1840 } 1841 1842 1843 /**Methods which should be called back by events of the implementation layer. 1844 * This class is used only for the implementation level of the graphic. It is not intent to use 1845 * by any application. It is public because the implementation level should accesses it. 1846 */ 1847 public abstract static class ImplAccess implements GralWidgImpl_ifc { 1848 1849 /**What is changed in the dynamic data, see {@link GralWidget.DynamicData#whatIsChanged}. */ 1850 public static final int chgText = 1, chgColorBack=2, chgColorText=4, chgFont = 8, chgColorLine = 0x10; 1851 1852 public static final int chgEditable = 0x20; 1853 1854 public static final int chgVisibleInfo = 0x10000, chgObjects = 0x20000, chgFloat = 0x40000, chgIntg = 0x80000; 1855 1856 public static final int chgFocus = 0x10000000; 1857 1858 public static final int chgPos = 0x20000000, chgVisible = 0x40000000, chgInvisible = 0x80000000; 1859 1860 /**This is only documentation. These bits are used specialized in derived classes.*/ 1861 public static final int chgBitsDerived = 0x0ff0ff00; 1862 1863 public final GralWidget widgg; 1864 1865 1866 /**Aggregation to the widget implementation which resolves the required implementation methods. */ 1867 protected GralWidgetImpl_ifc wdgimpl; 1868 1869 /**Bounds of the implementation widget in its container. null if not used. */ 1870 public GralRectangle pixBounds; 1871 1872 @Deprecated protected ImplAccess(GralWidget widgg, GralMng mng){ 1873 this(widgg); 1874 } 1875 1876 1877 /**Constructs the base of the graphic implemantion widget wrapper (SWT, AWT). 1878 * Stores the reference to the GralWidget in this.{@link #widgg} 1879 * Stores the reference to the graphic implementation widget in {@link GralWidget#_wdgImpl} 1880 * Initializes the pos() from the given {@link GralMng#pos} if it is not given by construction. 1881 * @param widgg The associated derived class of GralWidget. 1882 */ 1883 protected ImplAccess(GralWidget widgg){ 1884 this.widgg = widgg; 1885 widgg._wdgImpl = this; 1886 1887 if(widgg._wdgPos ==null) { 1888 widgg._wdgPos = widgg.itsMng.getPosCheckNext(); 1889 widgg.registerWidget(); //yet now because before the panel was unknown 1890 } 1891 widgg.lastTimeSetVisible = System.currentTimeMillis(); 1892 } 1893 1894 1895 1896 1897 /**This method is not intent to call by user. It may be called from all widget implementation 1898 * if the focus of the widget is gained. Use {@link #setFocus()} to set a widget in the focus. 1899 * 1900 * It sets the html help for the widget and notifies the widgets in focus for the GralWidgetMng. 1901 * Don't override this method in the graphic implementation! 1902 * It should be overridden only in a Gral widget inheritance only if necessary. 1903 */ 1904 public void XXXfocusGained(){ 1905 //System.out.println(Assert.stackInfo("GralWidget - Debuginfo; focusgained", 1, 10)); 1906 if(widgg.htmlHelp !=null){ 1907 widgg.itsMng.setHtmlHelp(widgg.htmlHelp); 1908 } 1909 if(widgg.cfg.actionFocused !=null){ widgg.cfg.actionFocused.exec(KeyCode.focusGained, widgg); } 1910 //notify GralWidgetMng about focused widget. 1911 widgg.itsMng.notifyFocus(widgg); 1912 } 1913 1914 /**Sets the state of the widget whether it seams to be visible. 1915 * This method should not be invoked by the application. It is 1916 * @param visible 1917 */ 1918 public void setVisibleState(boolean visible){ 1919 widgg.setVisibleState(visible); 1920 } 1921 1922 /**Access method to GralWidget's method. */ 1923 protected GralUserAction actionShow(){ return widgg.cfg.actionShow; } 1924 1925 /**Access method to GralWidget's method. */ 1926 //protected GralUserAction actionChanging(){ return widgg.cfg.actionChanging; } 1927 1928 1929 /**Access method to {@link GralWidget#dyda}. */ 1930 protected GralWidget.DynamicData dyda(){ return widgg.dyda; } 1931 1932 //public void setWidgetImpl(GralWidgImpl_ifc widg, GralMng mng){ widgg.wdgImpl = widg; widgg.itsMng = mng; } 1933 1934 /**Notify that the text is changed in {@link GralWidget.DynamicData#bTextChanged} */ 1935 protected void setTextChanged(){ widgg.dyda.bTextChanged = true; } 1936 1937 /**Invoked on touching a widget. */ 1938 //protected void setTouched(){ widgg.dyda.bTouchedField = true; } 1939 1940 1941 /**Implementation routine to set receiving a drag event and initializes the drag feature of the widget. 1942 * A overridden routine should be implemented for the implementation graphic layer widget. 1943 * This routine is invoked when it isn't overridden, it throws an exception because the drag feature 1944 * isn't supported for the implementation. 1945 * @param dragType one of {@link org.vishia.util.KeyCode#dragFiles} or ..dragText 1946 */ 1947 protected void setDragEnable(int dragType) 1948 { //default implementation: causes an exception. The type must override it. 1949 throw new IllegalArgumentException("drag not supported for this widget type"); 1950 } 1951 1952 /**Implementation routine to set receiving a drop event and initializes the drop feature of the widget. 1953 * @param dropType one of {@link org.vishia.util.KeyCode#dropFiles} or ..dropText 1954 */ 1955 protected void setDropEnable(int dropType) 1956 { //default implementation: causes an exception. The type must override it. 1957 throw new IllegalArgumentException("drop not supported for this widget type"); 1958 } 1959 1960 1961 1962 /**Gets the bits what is changed in the widget's data. The bits are all definitions 1963 * starting with chg in this class. {@link #chgText} etc. 1964 * @return 1965 */ 1966 public int getChanged(){ return widgg.dyda.whatIsChanged.get(); } 1967 1968 public void acknChanged(int mask){ widgg.dyda.acknChanged(mask); } 1969 1970 1971 protected ActionChange getActionChange(ActionChangeWhen when){ return widgg.getActionChange(when); } 1972 1973 public static GralWidget gralWidgetFromImplData(Object data){ 1974 if(data instanceof GralWidget) return (GralWidget)data; 1975 else if(data instanceof GralWidget.ImplAccess) { 1976 return ((GralWidget.ImplAccess)data).widgg; 1977 } else return null; 1978 } 1979 1980 1981 /**This routine does not change the focus state in the implementation widget, 1982 * it denotes only that the GralWidget has the focus or not. 1983 * The method is static because it gets the widgg instance. 1984 * Note that it is not member of GralWidget itself because the application 1985 * should not invoke it (which may be possible on a public GralWidget-method). 1986 * @param widgg the GralWidget instance 1987 * @param focus true on focus gained, false on focus lost. 1988 */ 1989 public static void setFocused(GralWidget widgg, boolean focus){ 1990 widgg.bHasFocus = focus; 1991 if(focus == false) { widgg.dyda.bTouchedField = false; } 1992 } 1993 } 1994 1995 /**Not intent to get from user: The instance which's methods can be called from an event method of the implementation of the GralWidget. 1996 * Note: This Method is public only because the implementation in another package need to use it. 1997 * It should not be used by any application. */ 1998 //public MethodsCalledbackFromImplementation implMethodWidget_ = new MethodsCalledbackFromImplementation(); 1999 2000 2001 /**Returns the instance which extends the {@link ImplAccess} of this widget. 2002 * @return null if the widget has not an implementation yet. 2003 */ 2004 public ImplAccess getImpl(){ return _wdgImpl; } 2005 2006 2007 /**This time order calls the {@link #repaintGthread()} in the graphical thread. 2008 * It is used with delay and wind up whenever {@link #repaint(int, int)} with an delay is called. 2009 * If its executeOrder() runs, it is dequeued from timer queue in the {@link GralGraphicThread} 2010 * till the next request of {@link #repaint(int, int)} or {@link #repaint()}. 2011 */ 2012 private final GralGraphicTimeOrder repaintRequ = new GralGraphicTimeOrder("GralWidget.repaintRequ"){ 2013 @Override public void executeOrder() { 2014 if(_wdgImpl !=null) { _wdgImpl.repaintGthread(); }//Note: exception thrown in GralGraphicThread 2015 } 2016 @Override public String toString(){ return name + ":" + GralWidget.this.name; } 2017 }; 2018 2019 2020 /**Sets the state of the widget whether it seams to be visible. 2021 * This method should not be invoked by the application. It is 2022 * @param visible 2023 */ 2024 final public void setVisibleStateWidget(boolean visible){ 2025 bVisibleState = visible; 2026 String name = _wdgPos.panel == null ? "main window" : _wdgPos.panel.name; 2027 System.out.println((visible? "GralWidget set visible: " : "GralWidget set invisible: @") + name + ":" + toString()); 2028 lastTimeSetVisible = System.currentTimeMillis(); 2029 } 2030 2031 2032 public void setVisibleState(boolean visible){ 2033 setVisibleStateWidget(visible); 2034 } 2035 2036 2037 void stop(){ 2038 2039 } 2040 2041 2042 @Override @Deprecated 2043 public GralColor setBackgroundColor(GralColor color) 2044 { 2045 // TODO Auto-generated method stub 2046 return null; 2047 } 2048 2049 2050 @Override 2051 public void setBoundsPixel(int x, int y, int dx, int dy) 2052 { if(_wdgImpl !=null) _wdgImpl.setBoundsPixel(x, y, dx, dy); 2053 } 2054 2055 2056 @Override 2057 public GralColor setForegroundColor(GralColor color) 2058 { // TODO Auto-generated method stub 2059 return null; 2060 } 2061 2062 2063 //@Override 2064 public Object XXXgetWidgetImplementation() 2065 { if(_wdgImpl !=null) return _wdgImpl.getWidgetImplementation(); 2066 else return null; 2067 } 2068 2069 2070 //@Override 2071 public void XXXremoveWidgetImplementation() 2072 { if(_wdgImpl !=null) _wdgImpl.removeWidgetImplementation(); 2073 } 2074 2075 2076 //@Override 2077 public void XXXrepaintGthread() 2078 { 2079 if(_wdgImpl !=null) _wdgImpl.repaintGthread(); 2080 } 2081 2082 2083 //@Override 2084 public boolean XXXsetFocusGThread() 2085 { boolean ret; 2086 try{ 2087 if(_wdgImpl !=null) { 2088 ret = _wdgImpl.setFocusGThread(); 2089 bVisibleState = true; //may be set via the _wdgImpl too, but set additional if not done in _wdgImpl.setFocusGThread() 2090 } 2091 else ret = false; 2092 } catch(Exception exc){ 2093 System.err.println("GralWidget - setFocusGThread fails"); 2094 ret = false; 2095 } 2096 return ret; 2097 } 2098 2099 2100 /**Sets the implementation widget visible or not. 2101 * @see org.vishia.gral.base.GralWidgImpl_ifc#setVisibleGThread(boolean) 2102 */ 2103 //@Override 2104 public void XXXsetVisibleGThread(boolean bVisible){ 2105 try{ 2106 if(_wdgImpl !=null){ 2107 setVisibleState(bVisible); 2108 _wdgImpl.setVisibleGThread(bVisible); 2109 } 2110 } catch(Exception exc){ 2111 System.err.println("GralWidget - setFocusGThread fails"); 2112 } 2113 } 2114 2115} 2116