001package org.vishia.gral.swt; 002 003import java.io.IOException; 004 005import org.eclipse.swt.SWT; 006import org.eclipse.swt.events.FocusEvent; 007import org.eclipse.swt.events.FocusListener; 008import org.eclipse.swt.events.KeyListener; 009import org.eclipse.swt.events.ModifyEvent; 010import org.eclipse.swt.events.ModifyListener; 011import org.eclipse.swt.graphics.Font; 012import org.eclipse.swt.graphics.Point; 013import org.eclipse.swt.graphics.Rectangle; 014import org.eclipse.swt.widgets.Composite; 015import org.eclipse.swt.widgets.Label; 016import org.eclipse.swt.widgets.ScrollBar; 017import org.eclipse.swt.widgets.Text; 018import org.vishia.gral.base.GralGraphicTimeOrder; 019import org.vishia.gral.base.GralKeyListener; 020import org.vishia.gral.base.GralMng; 021import org.vishia.gral.base.GralPanelContent; 022import org.vishia.gral.base.GralTextBox; 023import org.vishia.gral.base.GralTextField; 024import org.vishia.gral.base.GralWidget; 025import org.vishia.gral.ifc.GralColor; 026import org.vishia.gral.ifc.GralFont; 027import org.vishia.gral.ifc.GralRectangle; 028import org.vishia.gral.ifc.GralTextFieldUser_ifc; 029import org.vishia.gral.ifc.GralUserAction; 030import org.vishia.gral.ifc.GralWidget_ifc; 031import org.vishia.gral.swt.SwtTextFieldWrapper.TextFieldKeyListener; 032import org.vishia.gral.swt.SwtTextFieldWrapper.TextFieldModifyListener; 033import org.vishia.util.KeyCode; 034 035public class SwtTextBox extends GralTextBox.GraphicImplAccess 036{ 037 038 /**Version and history 039 * <ul> 040 * <li>2014-08-16 Hartmut chg: GralTextBox not abstract, using GraphicImplAccess like new concept of all GralWidgets. 041 * <li>2012-01-06 Hartmut chg: The {@link #append(CharSequence)} etc. methods are implemented 042 * in this super class instead in the graphic layer implementation classes. Therefore 043 * the methods {@link #appendTextInGThread(CharSequence)} and {@link #setTextInGThread(CharSequence)} 044 * are defined here to implement in the graphic layer. The set- and apppend methods are <b>threadsafe</b> now. 045 * </ul> 046 * 047 * <b>Copyright/Copyleft</b>: 048 * For this source the LGPL Lesser General Public License, 049 * published by the Free Software Foundation is valid. 050 * It means: 051 * <ol> 052 * <li> You can use this source without any restriction for any desired purpose. 053 * <li> You can redistribute copies of this source to everybody. 054 * <li> Every user of this source, also the user of redistribute copies 055 * with or without payment, must accept this license for further using. 056 * <li> But the LPGL is not appropriate for a whole software product, 057 * if this source is only a part of them. It means, the user 058 * must publish this part of source, 059 * but don't need to publish the whole source of the own product. 060 * <li> You can study and modify (improve) this source 061 * for own using or for redistribution, but you have to license the 062 * modified sources likewise under this LGPL Lesser General Public License. 063 * You mustn't delete this Copyright/Copyleft inscription in this source file. 064 * </ol> 065 * If you are indent to use this sources without publishing its usage, you can get 066 * a second license subscribing a special contract with the author. 067 * 068 * @author Hartmut Schorrig = hartmut.schorrig@vishia.de 069 * 070 * 071 */ 072 @SuppressWarnings("hiding") 073 public final static String sVersion = "2014-08-16"; 074 075 076 /**Experience: use SwtTextFieldWrapper as composite? (instead superclass) 077 * 078 */ 079 @SuppressWarnings("unused") 080 private SwtTextFieldWrapper swtText; 081 082 /**It contains the association to the swt widget (Control) and the {@link SwtMng} 083 * and implements some methods of {@link GralWidgImpl_ifc} which are delegate from this. 084 */ 085 private final SwtWidgetHelper wdgh; 086 087 /*package private*/ Text textFieldSwt; 088 089 /**A possible prompt for the text field or null. */ 090 Label promptSwt; 091 092 093 protected SwtTextBox(GralTextBox widgg, SwtMng mng) 094 { widgg.super(widgg); //NOTE: superclass is a non static inner class of GralTextField. 095 Composite panelSwt = mng.getCurrentPanel(); 096 GralPanelContent gralPanel = mng.mng.getCurrentPanel(); 097 098 assert(panelSwt !=null); 099 textFieldSwt = new Text(panelSwt, SWT.MULTI|SWT.H_SCROLL|SWT.V_SCROLL); //;style); 100 textFieldSwt.setData(this); 101 super.wdgimpl = this.wdgh = new SwtWidgetHelper(textFieldSwt, mng); 102 textFieldSwt.addFocusListener(focusLstn); 103 textFieldSwt.setFont(mng.propertiesGuiSwt.stdInputFont); 104 textFieldSwt.setEditable(widgg.isEditable()); 105 textFieldSwt.setBackground(mng.propertiesGuiSwt.colorSwt(0xFFFFFF)); 106 textFieldSwt.addMouseListener(SwtGralMouseListener.mouseActionStd); 107 KeyListener swtKeyListener = new TextBoxKeyListener(mng.mng._impl.gralKeyListener); 108 textFieldSwt.addKeyListener(swtKeyListener); 109 TextBoxModifyListener modifyListener = new TextBoxModifyListener(); 110 textFieldSwt.addModifyListener(modifyListener); 111 112 mng.setPosAndSize_(widgg.pos(), textFieldSwt); 113 if(prompt() != null && promptStylePosition().equals("t")){ 114 final int yPixelField; 115 final Font promptFont; 116 int ySize = (int)(widgg.pos().height()); 117 switch(ySize){ 118 case 3: promptFont = mng.propertiesGuiSwt.smallPromptFont; 119 yPixelField = mng.propertiesGuiSwt.yPixelUnit() * 2 -3; 120 break; 121 case 2: promptFont = mng.propertiesGuiSwt.smallPromptFont; 122 yPixelField = (int)(1.5F * mng.mng.propertiesGui.yPixelUnit()); 123 break; 124 default: promptFont = mng.propertiesGuiSwt.smallPromptFont; 125 yPixelField = mng.mng.propertiesGui.yPixelUnit() * 2 -3; 126 }//switch 127 Rectangle boundsField = textFieldSwt.getBounds(); 128 Rectangle boundsPrompt = new Rectangle(boundsField.x, boundsField.y-3 //occupy part of field above, only above the normal letters 129 , boundsField.width, boundsField.height ); 130 131 if(promptStylePosition().equals("t")){ 132 boundsPrompt.height -= (yPixelField -4); 133 boundsPrompt.y -= 1; 134 135 boundsField.y += (boundsField.height - yPixelField ); 136 boundsField.height = yPixelField; 137 } 138 Label wgPrompt = new Label(panelSwt, 0); 139 //Text wgPrompt = new Text(((SwtPanel)pos.panel).getPanelImpl(), 0); 140 wgPrompt.setFont(promptFont); 141 wgPrompt.setText(prompt()); 142 Point promptSize = wgPrompt.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); 143 if(promptSize.x > boundsPrompt.width){ 144 boundsPrompt.width = promptSize.x; //use the longer value, if the prompt text is longer as the field. 145 } 146 textFieldSwt.setBounds(boundsField); 147 wgPrompt.setBounds(boundsPrompt); 148 } 149 mng.mng.registerWidget(widgg); 150 } 151 152 153 static void createTextBox(GralTextBox widgg, SwtMng mng){ 154 SwtTextBox widgetSwt = new SwtTextBox(widgg, (SwtMng)mng); 155 // 156 } 157 158 159 160 161 //@Override public Widget getWidgetImplementation(){ return textFieldSwt; } 162 //@Override public boolean setFocus(){ return textFieldSwt.setFocus(); } 163 164 @Override public GralRectangle getPixelPositionSize(){ return wdgh.getPixelPositionSize(); } 165 166 167 168 169 170 171 @Override public Object getWidgetImplementation() 172 { return textFieldSwt; 173 } 174 175 /* 176 177 @Override public String getText() 178 { 179 String oldText = textFieldSwt.getText(); 180 return oldText; 181 } 182 183 @Override public GralColor setBackgroundColor(GralColor color) 184 { return SwtWidgetHelper.setBackgroundColor(color, textFieldSwt); 185 } 186 187 188 @Override public GralColor setForegroundColor(GralColor color) 189 { return SwtWidgetHelper.setForegroundColor(color, textFieldSwt); 190 } 191 192 193 194 195 196 197 @Override public void setTextInGThread(CharSequence text){ 198 textFieldSwt.setText(text.toString()); 199 } 200 201 202 203 @Override public void appendTextInGThread(CharSequence text){ 204 textFieldSwt.append(text.toString()); 205 } 206 207 */ 208 209 210 @Override public void setBoundsPixel(int x, int y, int dx, int dy) 211 { textFieldSwt.setBounds(x,y,dx,dy); 212 } 213 214 215 216 217 @Override public void repaintGthread(){ 218 int catastrophicalCount = 0; 219 int chg; 220 if(textFieldSwt !=null){ //do nothing if the graphic implementation widget is removed. 221 GralWidget.DynamicData dyda = dyda(); 222 while( (chg = getChanged()) !=0){ //widgg.dyda.whatIsChanged.get(); 223 if(++catastrophicalCount > 10000) 224 throw new RuntimeException("atomic failed"); 225 if((chg & chgText) !=0 && dyda.displayedText !=null){ 226 textFieldSwt.setText(dyda.displayedText); 227 final int selectionStart, selectionEnd; 228 final int zText = dyda.displayedText.length(); 229 if(caretPos() <0){ 230 selectionEnd = dyda.displayedText.length(); selectionStart = selectionEnd; // -1; 231 } 232 else if(caretPos() >0){ 233 selectionEnd = caretPos() > zText ? zText : caretPos(); 234 selectionStart = selectionEnd; // -1; 235 } else { 236 assert(caretPos() ==0); 237 selectionEnd = selectionStart =-1; //dont call 238 } 239 if(selectionStart >=0){ 240 textFieldSwt.setSelection(selectionStart, selectionEnd); 241 } 242 } 243 if((chg & chgAddText) !=0) { 244 textFieldSwt.append(getAndClearNewText()); 245 } 246 if((chg & chgColorText)!=0){ 247 SwtProperties props = wdgh.mng.propertiesGuiSwt; 248 if(dyda.textColor !=null){ 249 textFieldSwt.setForeground(props.colorSwt(dyda.textColor)); 250 } 251 if(dyda.backColor !=null){ 252 textFieldSwt.setBackground(props.colorSwt(dyda.backColor)); 253 } 254 if(dyda.textFont !=null){ 255 textFieldSwt.setFont(props.fontSwt(dyda.textFont)); 256 } 257 } 258 if((chg & chgEditable)!=0){ 259 textFieldSwt.setEditable(true); 260 } 261 if((chg & chgNonEditable)!=0){ 262 textFieldSwt.setEditable(false); 263 } 264 265 if((chg & chgViewTrail)!=0) { 266 ScrollBar scroll = textFieldSwt.getVerticalBar(); 267 int maxScroll = scroll.getMaximum(); 268 scroll.setSelection(maxScroll); 269 textFieldSwt.update(); 270 } 271 if((chg & chgCursor) !=0){ 272 textFieldSwt.setSelection(caretPos()); 273 } 274 if((chg & chgVisible) !=0) { 275 textFieldSwt.getShell().setVisible(true); 276 } 277 if((chg & chgInvisible) !=0) { 278 textFieldSwt.getShell().setVisible(false); 279 } 280 if((chg & chgColorText) !=0){ textFieldSwt.setForeground(wdgh.mng.getColorImpl(dyda().textColor)); } 281 if((chg & chgColorBack) !=0){ textFieldSwt.setBackground(wdgh.mng.getColorImpl(dyda().backColor)); } 282 textFieldSwt.redraw(); 283 acknChanged(chg); 284 } 285 } 286 } 287 288 289 290 291 292 @Override public boolean setFocusGThread() 293 { return SwtWidgetHelper.setFocusOfTabSwt(textFieldSwt); 294 } 295 296 297 @Override public void setVisibleGThread(boolean bVisible) { super.setVisibleState(bVisible); wdgh.setVisibleGThread(bVisible); } 298 299 300 @Override public void removeWidgetImplementation() 301 { 302 if(textFieldSwt !=null) { 303 textFieldSwt.dispose(); 304 textFieldSwt = null; 305 } 306 if(promptSwt !=null){ 307 promptSwt.dispose(); 308 promptSwt = null; 309 } 310 } 311 312 313 protected class TextBoxKeyListener extends SwtKeyListener 314 //protected SwtKeyListener swtKeyListener = new SwtKeyListener(SwtTextBox.this.swtWidgHelper.mng._impl.gralKeyListener) 315 { 316 317 public TextBoxKeyListener(GralKeyListener keyAction) 318 { super(keyAction); 319 } 320 321 @Override public final boolean specialKeysOfWidgetType(int key, GralWidget_ifc widgg, Object widgImpl){ 322 boolean bDone = true; 323 if(KeyCode.isWritingKey(key)){ 324 setTextChanged(); 325 } 326 boolean bUserOk; 327 GralTextFieldUser_ifc user = user(); 328 if(user !=null){ 329 Point selection = textFieldSwt.getSelection(); 330 bUserOk = user.userKey(key 331 , textFieldSwt.getText() 332 , textFieldSwt.getCaretPosition() 333 , selection.x, selection.y); 334 } else { bUserOk = false; } 335 // 336 if(!bUserOk ){ //user has not accept the key 337 if(KeyCode.isWritingOrTextNavigationKey(key)) return true; 338 switch(key){ 339 case KeyCode.ctrl + 'a': { 340 textFieldSwt.selectAll(); 341 } break; 342 default: bDone = false; 343 } 344 } 345 return bDone; 346 } 347 348 349 350 } 351 352 353 354 355 protected class TextBoxModifyListener implements ModifyListener{ 356 @Override public void modifyText(ModifyEvent ev) { 357 String text = textFieldSwt.getText(); 358 SwtTextBox.super.dyda().displayedText = text; 359 //System.out.println("actionText"); 360 //SwtTextFieldWrapper.super.caretPos = textFieldSwt.getCaretPosition(); 361 GralWidget_ifc.ActionChange action = getActionChange(GralWidget_ifc.ActionChangeWhen.onAnyChgContent); 362 if(action !=null){ 363 Object[] args = action.args(); 364 if(args == null){ action.action().exec(KeyCode.valueChanged, widgg, text); } 365 else { action.action().exec(KeyCode.valueChanged, widgg, args, text); } 366 } 367 //if(dyda.displayedText !=null){ 368 //textFieldSwt.setText(dyda.displayedText); 369 //} 370 } 371 372 } 373 374 protected FocusListener focusLstn = new FocusListener() 375 { 376 377 @Override 378 public void focusLost(FocusEvent e) 379 { 380 System.err.println("TextBox focus lost"); 381 } 382 383 @Override 384 public void focusGained(FocusEvent e) 385 { 386 System.err.println("TextBox focus gained"); 387 } 388 }; 389 390 391}