001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2009 Sun Microsystems, Inc.
015 * Portions Copyright 2015-2016 ForgeRock AS.
016 */
017package org.opends.guitools.controlpanel.ui.components;
018
019import javax.swing.text.AttributeSet;
020import javax.swing.text.BadLocationException;
021import javax.swing.text.DocumentFilter;
022import javax.swing.text.JTextComponent;
023
024/** Document filter used to update properly a text component displaying a time. */
025public class TimeDocumentFilter extends DocumentFilter
026{
027  private JTextComponent tf;
028
029  /**
030   * Constructor.
031   * @param tf the text component associated with the document.
032   */
033  public TimeDocumentFilter(JTextComponent tf)
034  {
035    this.tf = tf;
036  }
037
038  @Override
039  public void insertString(DocumentFilter.FilterBypass fb, int offset,
040      String text, AttributeSet attr)
041  throws BadLocationException
042  {
043    int previousLength = fb.getDocument().getLength();
044    fb.insertString(offset, text.replaceAll("[^0-9]", ""), attr);
045    trimPosition(fb, text, offset, previousLength);
046  }
047
048  @Override
049  public void remove(DocumentFilter.FilterBypass fb, int offset,
050      int length)
051  throws BadLocationException
052  {
053    String text = fb.getDocument().getText(offset, length);
054    int index = text.indexOf(":");
055    if (index == -1)
056    {
057      fb.remove(offset, length);
058    }
059    else
060    {
061      // index value is relative to offset
062      if (index > 0)
063      {
064        fb.remove(offset, index);
065      }
066      if (index < length - 1)
067      {
068        fb.remove(offset + index + 1, length - index -1);
069      }
070    }
071    updateCaretPosition(fb);
072  }
073
074  @Override
075  public void replace(DocumentFilter.FilterBypass fb, int offset,
076      int length, String text, AttributeSet attr)
077  throws BadLocationException
078  {
079    int previousLength = fb.getDocument().getLength();
080
081    String t = fb.getDocument().getText(offset, length);
082    int index = t.indexOf(":");
083    fb.replace(offset, length, text.replaceAll("[^0-9]", ""), attr);
084    if (index != -1)
085    {
086      if (fb.getDocument().getLength() >= 2)
087      {
088        fb.insertString(2, ":", attr);
089      }
090      else
091      {
092        fb.insertString(fb.getDocument().getLength(), ":", attr);
093      }
094    }
095
096    trimPosition(fb, text, offset, previousLength);
097  }
098
099  private void trimPosition(DocumentFilter.FilterBypass fb, String newText,
100      int offset, int previousLength)
101  throws BadLocationException
102  {
103    String allText =
104      fb.getDocument().getText(0, fb.getDocument().getLength());
105    int index = allText.indexOf(':');
106    if (index != -1 && newText.length() == 1)
107    {
108      int minuteLength = allText.length() - index - 1;
109      int hourLength = index;
110
111      if (minuteLength > 2 || hourLength > 2)
112      {
113        if (offset < previousLength)
114        {
115          fb.remove(offset + 1, 1);
116        }
117        else
118        {
119          fb.remove(previousLength, 1);
120        }
121      }
122    }
123    updateCaretPosition(fb);
124  }
125
126  private void updateCaretPosition(DocumentFilter.FilterBypass fb)
127  throws BadLocationException
128  {
129    String allText =
130      fb.getDocument().getText(0, fb.getDocument().getLength());
131    int index = allText.indexOf(':');
132    if (index != -1)
133    {
134      int minuteLength = allText.length() - index - 1;
135      int hourLength = index;
136      int caretPosition = tf.getCaretPosition();
137
138      if (minuteLength >= 2 &&
139          caretPosition == allText.length())
140      {
141        tf.setCaretPosition(0);
142      }
143      else if (hourLength == caretPosition)
144      {
145        if (hourLength >= 2)
146        {
147          tf.setCaretPosition(3);
148        }
149        else if (hourLength == 1)
150        {
151          char c = allText.charAt(0);
152          if (c != '0' && c != '1' && c != '2')
153          {
154            tf.setCaretPosition(2);
155          }
156        }
157      }
158      else if (hourLength + 1 == caretPosition)
159      {
160        if (hourLength == 1)
161        {
162          char c = allText.charAt(0);
163          if (c == '0' || c == '1' || c == '2')
164          {
165            tf.setCaretPosition(caretPosition - 1);
166          }
167        }
168        else if (hourLength == 0)
169        {
170          tf.setCaretPosition(caretPosition - 1);
171        }
172      }
173    }
174    if (allText.length() == 1)
175    {
176      tf.setCaretPosition(0);
177    }
178  }
179}