    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}