[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 200
  • Last Modified:

Text validation

Hi,

Could someone point me in the right direction here please?
What is the best way to validate a text field which is for filenames? Should I just wait for entry confirmation and then validate or is it nice to create a general class which could be added as a listener to all appropriate text fields?
  Also - in Eclipse when you create a new class it validates the filename on-the-fly -> you must enter a valid file/class name which doesnt already exist. Perhaps I would like to implement this - HOW??

Thanks,
Cathal.
0
cathalmchale
Asked:
cathalmchale
  • 31
  • 20
  • 5
  • +2
7 Solutions
 
zzynxSoftware engineerCommented:
>> it validates the filename on-the-fly
By using your own Document for the textfield
0
 
cathalmchaleAuthor Commented:
>> By using your own Document for the textfield

Sorry, what??  you mean extend JTextField or something?
0
 
zzynxSoftware engineerCommented:
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
zzynxSoftware engineerCommented:
0
 
zzynxSoftware engineerCommented:
So in insertString() you do your validation (e.g. checking if the file already exists)
According to the validation you "accept" the entered character(s) or not.
0
 
NaeemgCommented:
u create a file with given name , if it throws any exception then it means the given name is invalid. otherwise OK.
0
 
objectsCommented:
Use JFileChooser
0
 
zzynxSoftware engineerCommented:
I agree with objects that using JFileChooser is the best. That's what it is made for eventually.
Just don't know how thight you're bound to the use of a text field however.
0
 
cathalmchaleAuthor Commented:
Well its actually a Wizard similiar to the new class wizard in eclipse.  so i dont think the file-chooser would be appropriate
0
 
zzynxSoftware engineerCommented:
Then I'd use the document approach
0
 
objectsCommented:
> so i dont think the file-chooser would be appropriate

why not?
0
 
cathalmchaleAuthor Commented:
>> why not?

perhaps it is?  note that selecting an appropriate file name is step 1 of 5 in the wizard - is it easy to extend and personalise the file-chooser?? Any examples close to what i am looking much appreciated
0
 
zzynxSoftware engineerCommented:
Don't know if it possible with JFileChooser to avoid that the user chooses a filename that already exists...
0
 
CEHJCommented:
>>What is the best way to validate a text field which is for filenames?

Why not create a File and then call the appropriate methods on it?
0
 
cathalmchaleAuthor Commented:
>> Why not create a File and then call the appropriate methods on it?

I have a new file object with the name the user wants to give it.  is the only way to test if its a valid file(name) to create the file and then check if it exists - this seems a little "expensive", also if it is this way should i use the create tempory file method??

0
 
zzynxSoftware engineerCommented:
>> if it is this way should i use the create tempory file method??
No.
Use createNewFile():
Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist.
0
 
zzynxSoftware engineerCommented:
>> is the only way to test if its a valid file(name) to create the file and then check if it exists
Forget the previous. You can simply call exists() on the File object to check if it exist already
(See http://javaalmanac.com/egs/java.io/Exists.html)
0
 
cathalmchaleAuthor Commented:
>> Forget the previous. You can simply call exists() on the File object to check if it exist already

I check for 2 things:
 Problem 1: file already exists
 Problem 2: invalid file identifier (user has typed a shitty name!!)

so its problem 2 thats the problem!! :)  solution?? cheers
0
 
zzynxSoftware engineerCommented:
>> Problem 2: invalid file identifier (user has typed a shitty name!!)
I expect createNewFile() to throw an IOException in that case

So,

      File fTmp = new File(....); // whatever they entered
      try {
           fTmp.createNewFile();
           fTmp.delete();
      } catch (IOException ex) {
          // Invalid file name
      }
0
 
cathalmchaleAuthor Commented:
I now have a class
public class FilenameValidation extends PlainDocument

in another class i do
// the above document class
validation = new FilenameValidation(directory, Configuration.SUFFIX_XML, fileExists, invalidName);
validation.addDocumentListener(this);
// set document of the textfield
titlePage.getNameField().setDocument(validation);

so i have added this class as a document listener - thus i inherit the methods
  public void insertUpdate(DocumentEvent e)
  {
  }
  public void removeUpdate(DocumentEvent e)
  {
  }
  public void changedUpdate(DocumentEvent e)
  {
  }

i just want the changes to occur    ->  like calling a super.insertUpdate .. or whatever!  but obviously i'm not extending the class so cant!

Heres what im doing:
i add the FilenameValidation to the text field  -->  they can type whatever they want, but then i wanted the listener to check if file valid using my class FilenameValidation -> if its not valid then it will disable the next and finish buttons
0
 
zzynxSoftware engineerCommented:
I doubt if you need a DocumentListener.
Shouldn't you just override insertString() in FilenameValidation
0
 
zzynxSoftware engineerCommented:
insertString() is triggered for every change that occurs in your textfield
0
 
cathalmchaleAuthor Commented:
>> Shouldn't you just override insertString() in FilenameValidation
I have - here it is:

public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException
  {
    String fileName = this.getText(0, this.getLength());
    if(extension != null)
      fileName = fileName + extension;
   
    // is this a valid file?
    File file = new File(directory, fileName);
    if(file.exists())
    {
      validFile = false;
      problem = fileExists + ": '" + this.getText(0, this.getLength()) + "'";
    }
    else
    {
      try
      {
        file.createNewFile();
        file.delete();
        validFile = true;
        problem = "";
      }
      catch (IOException ex)
      {
************
        validFile = false;
        problem = invalidName + ": '" + this.getText(0, this.getLength()) + "'";
      }
    }
   
    super.insertString(offset, str, attr);
  }

so i thought a listener which could check each time the value of ******** validFile above -> then report the error / enable / diable Next button etc. ??
0
 
zzynxSoftware engineerCommented:
Why not passing an instance of whatever object you need in the FilenameValidation constructor and then use it:

Some kind of:

catch (IOException ex) {
        theObjectYouPassed.reportException(problem, ....);
}
0
 
zzynxSoftware engineerCommented:
...which can also perform additional things (like disabling buttons,...)
0
 
zzynxSoftware engineerCommented:
Have to go offline now.
See you.
0
 
cathalmchaleAuthor Commented:
thanks ;-)
0
 
CEHJCommented:
Why would you override insertString? Surely what you should do is to ask the user to choose a file name, then use it? The 'use it' stage is when you need to validate, which could be done by a button press, say.
0
 
cathalmchaleAuthor Commented:
>> Why would you override insertString? Surely what you should do is to ask the user to choose a file name, then use it? The 'use it' stage is when you need to validate, which could be done by a button press, say.

I suggested looking at the Eclipse "new class" type wizard - check it out you'll see what im after
0
 
cathalmchaleAuthor Commented:
I have a further problem!  When the user types a backspace things go wrong.  all i need to know is
if  String s     is a backspace
how do i do :   s.equals(**backspace**)

Cheers ;-)
0
 
CEHJCommented:
>>the Eclipse "new class" type wizard - check it out you'll see what im after

Ah - got a problem there - don't have it and no room on my machine to install it.

My point was centred around the fact that the insertString method is incremental. Therefore, unless you post a fully-formed file name into the text field, the method is going to be called every time you enter a single character, which is not appropriate
0
 
CEHJCommented:
I didn't see your last before i posted my last - you can probably see the connection ;-)
(The incrementality works in reverse too)
0
 
cathalmchaleAuthor Commented:
I want it called everytime they enter a character - the instant the filename becomes invalid (already exists / badly formed name) then the next and finish buttons are disabled and the warning displayed
0
 
objectsCommented:
you need to implement all 3 methods  insertUpdate, removeUpdate, and changedUpdate.
you get informed about changes to the text, not what keys were pressed.

0
 
cathalmchaleAuthor Commented:
>>  you need to implement all 3 methods  insertUpdate, removeUpdate, and changedUpdate.

so i'm back to using the listener again now!!
0
 
CEHJCommented:
>>/ badly formed name)

Wouldn't this, by virtue of the way you intend to do this, be the normal state?
0
 
zzynxSoftware engineerCommented:
>> so i'm back to using the listener again now!!
Not at all.

>> I have a further problem!  When the user types a backspace things go wrong
Sure your insertString() is triggered then? For me it isn't...
0
 
cathalmchaleAuthor Commented:
OK i use a validation class which extends PlainDocument, and you can see the insertString method posted above.
Perhaps instead i should just attach a default document to the textfield, then add a document listener and then do this insert string type validation locally??

does this sound more correct?????
0
 
zzynxSoftware engineerCommented:
Adapt your insertString() code as follows:

Replace

>>    String fileName = this.getText(0, this.getLength());
>>    if(extension != null)
>>        fileName = fileName + extension;

by

        if (s == null || s.length() == 0)
             return;
        StringBuffer t = new StringBuffer(getLength() + s.length());
        t.append(getText(0, index));
        t.append(s);
        t.append(getText(index, getLength() - index));
        String fileName = t.toString();
        if(extension != null)
           fileName = fileName + extension;
0
 
zzynxSoftware engineerCommented:
Sorry replace "s" by "str" (2nd parameter)
0
 
cathalmchaleAuthor Commented:
>> Sure your insertString() is triggered then? For me it isn't...

actually no it isnt, thats the problem! so they type an invalid name - warning shown - they hit backspace to make it valid again, but because insertString not called i do not recognise this
0
 
zzynxSoftware engineerCommented:
This code makes it even work when you copy/paste some characters in the middle of the name you already typed:

e.g.
1) You have:  MyName
2) You copy "File" to the clipboard
3) You put the cursor before the 'N'
4) You paste
5) You become "MyFileName"
0
 
zzynxSoftware engineerCommented:
>> actually no it isnt, thats the problem!
I see.  (Nevertheless I think the above changes are needed)

Thinking...
0
 
cathalmchaleAuthor Commented:
I dont fully understand your code - what is the variable "index" ?? and then of course this backspace problem, perhaps i do need to follow the listener idea?
0
 
zzynxSoftware engineerCommented:
>> what is the variable "index" ??
Oh, another one to replace, that's your offset (the 1st argument)

>> perhaps i do need to follow the listener idea?
Maybe yes indeed.
0
 
zzynxSoftware engineerCommented:
In that case (doc listener) write your document listener which you add to the document of your JTextField

  public void insertUpdate(DocumentEvent e) {
     validate(e);
  }
  public void removeUpdate(DocumentEvent e) {
     validate(e);
  }
  public void changedUpdate(DocumentEvent e) {
     validate(e);
  }

  private void validate(DocumentEvent e) {
     Document doc  = e.getDocument();
     String text = doc.getText(0, doc.getLength());

     // Do your filename checking here
  }
0
 
zzynxSoftware engineerCommented:
So,

public class MyDocListener implements DocumentListener {

  public DocumentListener() {  // or with one parameter if you need it to report on
  }

  public void insertUpdate(DocumentEvent e) {
     validate(e);
  }
  public void removeUpdate(DocumentEvent e) {
     validate(e);
  }
  public void changedUpdate(DocumentEvent e) {
     validate(e);
  }

  private void validate(DocumentEvent e) {
     Document doc  = e.getDocument();
     String text = doc.getText(0, doc.getLength());

     // Do your filename checking here
  }

}

together with

yourTextField.getDocument().addDocumentListener( new MyDocListener() );
0
 
zzynxSoftware engineerCommented:
Typo:
>> public DocumentListener()
should have been
      public MyDocListener()
0
 
cathalmchaleAuthor Commented:
Yup the document listener was certainly the way to go!! (and then i even had access to the textField.getText() !!!)
thanks EVERYONES help.

1 last question - i add a label (with icon) to display any problems
If no problem then icon and label = "" and null
This makes the overall content pane "jump around" - whats the best way to solve this? just fix size?- inwhich case i just want to fix the height and not width!
How should i do this?

i shall have to deliberate as to how to distribut points,
cheers ;-)
0
 
zzynxSoftware engineerCommented:
>> This makes the overall content pane "jump around" - whats the best way to solve this?
Chosing such a layout in which you don't have that phenomenon ;°)

e.g. Place the label in the south of a (wide enough) panel having the borderlayout

>>i shall have to deliberate as to how to distribut points
Award all comments that *really* helped you and you're done.
0
 
cathalmchaleAuthor Commented:
>> Chosing such a layout in which you don't have that phenomenon ;°)

I wish!!
not so easy in this case - the label can either be  16*16 icon and some text, or no icon no text (invisible!)
i could place it north but doesnt help!

JPanel content = new JPanel(new BorderLayout());
      // file already exists / invalid name label
      JPanel labelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
      fileProblem = new JLabel();

      labelPanel.add(fileProblem);
      content.add(labelPanel, BorderLayout.NORTH);
      // the title page content
      content.add(titlePage, BorderLayout.CENTER);
      //JideSwingUtilities.setOpaqueRecursively(titlePage, false);
      return content;
0
 
zzynxSoftware engineerCommented:
Don't understand:

If your titlePage which is in the center has the preferred width of let's say 400,
your panel in the north will have 400 pixels available too. (That's how a BorderLayout works)

Then, the label placed in the north (no matter if it has icon/text or not) always has 400 pixels to use.
Then why should there be jumping around?
0
 
zzynxSoftware engineerCommented:
>> always has 400 pixels to use.
always has 400 pixels available to use.
0
 
cathalmchaleAuthor Commented:
>> Then why should there be jumping around?

the width aint the problem its the height
0
 
zzynxSoftware engineerCommented:
And this doesn't help?

fileProblem.setPreferredSize( new Dimension(100, 17) );
fileProblem.setMinimumSize( new Dimension(10, 17) );
fileProblem.setMaximumSize( new Dimension(Integer.MAX_VALUE, 17) );
0
 
zzynxSoftware engineerCommented:
Maybe you'll have to repeat those lines after each occurrence of

fileProblem.setIcon(...);
fileProblem.setText(...);
0
 
cathalmchaleAuthor Commented:
yeah for sure it does but a number of times in the past i would have liked to have been able to specify 1 and allow the other to be chosen by the component itself:
i tried this but it didnt work:

JPanel content = new JPanel(new BorderLayout());
      // file already exists / invalid name label
      JPanel labelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
 {
        public Dimension getMinimumSize()
        {
          return new Dimension(fileProblem.getWidth(), 17);
        }
      };
      fileProblem = new JLabel();
     
      labelPanel.add(fileProblem);
      content.add(labelPanel, BorderLayout.NORTH);
      // the title page content
      content.add(titlePage, BorderLayout.CENTER);
      //JideSwingUtilities.setOpaqueRecursively(titlePage, false);
      return content;
0
 
zzynxSoftware engineerCommented:
Try

public class MyLabel extends JLabel {

   public Dimension getMinimumSize() {
       return new Dimension(super.getMinimumSize().width, 17);
   }
   public Dimension getMaximumSize() {
       return new Dimension(super.getMaximumSize().width, 17);
   }
   public Dimension getPreferredSize() {
       return new Dimension(super.getPreferredSize().width, 17);
   }

}

Have to go ofline again. Sorry.
Success
0
 
cathalmchaleAuthor Commented:
actually this works, thanks:

JPanel labelPanel = new JPanel(new FlowLayout(FlowLayout.LEFT))
      {
        public Dimension getMinimumSize()
        {
          return new Dimension(fileProblem.getWidth(), 25);
        }
        public Dimension getPreferredSize()
        {
          return getMinimumSize();
        }
      };
0
 
zzynxSoftware engineerCommented:
Thanks for accepting
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

  • 31
  • 20
  • 5
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now