001: /*
002: * Created on 05/01/2004
003: *
004: * ============================================================================
005: * GNU Lesser General Public License
006: * ============================================================================
007: *
008: * Swing Components - visit http://sf.net/projects/gfd
009: *
010: * Copyright (C) 2004 Igor Regis da Silva Simões
011: *
012: * This library is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU Lesser General Public
014: * License as published by the Free Software Foundation; either
015: * version 2.1 of the License, or (at your option) any later version.
016: *
017: * This library is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
020: * Lesser General Public License for more details.
021: *
022: * You should have received a copy of the GNU Lesser General Public
023: * License along with this library; if not, write to the Free Software
024: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
025: */
026:
027: package br.com.gfpshare.beans;
028:
029: import java.awt.Color;
030: import java.awt.Component;
031: import java.awt.Dimension;
032: import java.awt.Toolkit;
033: import java.awt.event.ActionEvent;
034: import java.awt.event.ActionListener;
035: import java.awt.event.FocusListener;
036: import java.io.Serializable;
037: import java.text.DateFormat;
038: import java.text.ParseException;
039: import java.text.SimpleDateFormat;
040: import java.util.Calendar;
041: import java.util.Date;
042:
043: import javax.swing.JButton;
044: import javax.swing.JFormattedTextField;
045: import javax.swing.JPanel;
046: import javax.swing.event.AncestorEvent;
047: import javax.swing.event.AncestorListener;
048: import javax.swing.event.EventListenerList;
049: import javax.swing.text.DateFormatter;
050: import javax.swing.text.DefaultFormatterFactory;
051:
052: /**
053: * Classe que representa um componente composto de um JFormattedTextField e um JButton, sendo que o JFormattedTextField é responssável por exibir uma String que
054: * representa uma data, assim como validar as String´s digitadas pelo usuário; o JButton é responssável por acionar um componente que implemente a interface
055: * ICalendar, o qual exibirá uma forma visual do usuário selecionar uma data. <br>
056: * <br>
057: * Atualmente existem dois componentes que implementam a interface ICalendar. ICalendarFrame e ICalendarWindow, ambos podem ser passados para o contrutor desta
058: * classe. O componete padrão é uma instância de ICalendarFrame, que será usada caso não seja passada qualquer outra para o construtor da classe.
059: *
060: * @author Igor Regis da Silva Simoes
061: * @created 20/01/2004
062: * @see ICalendar
063: */
064: public class ZCalendarTextField extends JPanel implements Serializable,
065: ICalendarField, AncestorListener, RequiredField {
066: /**
067: * Campo de texto que exibe a data e permite edição pelo usuário
068: */
069: private JFormattedTextField text;
070:
071: /**
072: * Botão que aciona o calendario
073: */
074: private JButton change;
075:
076: /**
077: * Calendario que fornece uma forma gráfica de seleção da data
078: */
079: private ICalendar calendario = null;
080:
081: /**
082: * Componente com o formato da data para exibição em String
083: */
084: private DateFormat format;
085:
086: /**
087: * Lista de listeners de eventos deste componente
088: */
089: private EventListenerList listeners = new EventListenerList();
090:
091: /**
092: * Cria uma nova instancia de ICalendarTextField, tendo como padrão um ICalendarFrame, para edição visual da data pelo ususário.
093: */
094: public ZCalendarTextField() {
095: format = DateFormat.getDateInstance(DateFormat.MEDIUM);
096: format.setCalendar(Calendar.getInstance());
097:
098: DateFormatter formatoDataExibicao = new DateFormatter(format);
099: DateFormatter formatoDataEdicao = new DateFormatter(
100: new SimpleDateFormat("ddMMyyyy"));
101:
102: setOpaque(false);
103: setLayout(null);
104: text = new JFormattedTextField();
105: text.setFormatterFactory(new DefaultFormatterFactory(
106: formatoDataExibicao, formatoDataExibicao,
107: formatoDataEdicao));
108: text.addActionListener(new InnerAction());
109: text.setPreferredSize(new Dimension(100, 24));
110: add(text);
111:
112: change = new JButton("...");
113: change.addActionListener(new InnerAction());
114: change.setPreferredSize(new Dimension(100, 24));
115: add(change);
116:
117: setName("ICalandarTextField");
118: setPreferredSize(new Dimension(100, 26));
119:
120: this .addAncestorListener(this );
121: }
122:
123: /**
124: * Cria uma instancia de ICalendarTextField com uma novo formato de exibição para a data, tendo como padrão um ICalendarFrame, para edição visual da data
125: * pelo ususário.
126: *
127: * @param f Configuração do formato
128: */
129: public ZCalendarTextField(
130: JFormattedTextField.AbstractFormatterFactory f) {
131: this ();
132: text.setFormatterFactory(f);
133: }
134:
135: /**
136: * Cria uma instancia de ICalendarTextField com uma novo formato de exibição para a data, tendo como componente de edição visual da data o que é passado
137: * como parâmetro.
138: *
139: * @param calendario Calendário que será exibido pelo componente
140: */
141: public ZCalendarTextField(ICalendar calendario) {
142: this ();
143: this .calendario = calendario;
144: calendario.setVisible(false);
145: calendario.setTextComponent(this );
146: change.setEnabled(true);
147: }
148:
149: /**
150: * Determina as medidas do componete e de seus subcomponentes.
151: *
152: * @param x Posição X do componente
153: * @param y Posição Y do componente
154: * @param width Comprimento do componente
155: * @param height Altura do componente
156: */
157: @Override
158: public void setBounds(int x, int y, int width, int height) {
159: super .setBounds(x, y, width, height);
160: text.setBounds(0, 0, width - 22, height);
161: change.setBounds(width - 20, 0, 20, height);
162: }
163:
164: /**
165: * Determina um novo formato para exibição da data pelo componete.
166: *
167: * @param f Configuração do formato
168: */
169: public void setMask(JFormattedTextField.AbstractFormatterFactory f) {
170: text.setFormatterFactory(f);
171: }
172:
173: /**
174: * Retorna o conteúdo do componete (data) em forma de String.
175: *
176: * @return Data
177: */
178: public String getText() {
179: return text.getText();
180: }
181:
182: /**
183: * Atribui uma nova data a ser utilizada pelo componente.
184: *
185: * @param datestring Data
186: */
187: public void setText(String datestring) {
188: text.setValue(datestring);
189: fireDataAlterada();
190: }
191:
192: /**
193: * Usado para setar a data do componente através de um Calendar Este métod é thread safe pois pode ser chamado simultaneamente pelas threads que atribuem os
194: * valores de dia, mes a ano.
195: *
196: * @param timeKeeper Calendário possuindo a data a ser exibida pelo componente
197: */
198: public synchronized void setCalendar(Calendar timeKeeper) {
199: format.setCalendar(timeKeeper);
200: text.setText(format.format(format.getCalendar().getTime()));
201: fireDataAlterada();
202: }
203:
204: /**
205: * Usado para retornar a data do componente através de um Calendar
206: *
207: * @return Calendário possuindo a data exibida pelo componente
208: */
209: public Calendar getCalendar() {
210: return format.getCalendar();
211: }
212:
213: /**
214: * Usado para setar a data do componente através de um Date
215: *
216: * @param time Date possuindo a data a ser exibida pelo componente
217: */
218: public void setDate(Date time) {
219: text.setText(time == null ? "" : format.format(time));
220: fireDataAlterada();
221: }
222:
223: /**
224: * Usado para setar a data do componente através de um Date
225: *
226: * @return Data atual do componente
227: */
228: public Date getDate() {
229: if (text.getText().trim().equals(""))
230: return null;
231: return format.getCalendar().getTime();
232: }
233:
234: /**
235: * Usado para Habilitar e desabilitar o componente
236: *
237: * @param enabled
238: */
239: @Override
240: public void setEnabled(boolean enabled) {
241: text.setEnabled(enabled);
242: change.setEnabled(enabled);
243: }
244:
245: /**
246: * @see javax.swing.event.AncestorListener#ancestorAdded(javax.swing.event.AncestorEvent)
247: */
248: public void ancestorAdded(AncestorEvent event) {
249: if (calendario != null) {
250: calendario.setTextComponent(this );
251: if (isEnabled() && calendario.isAbilitado())
252: calendario.setVisible(true);
253: }
254: }
255:
256: /**
257: * @see javax.swing.event.AncestorListener#ancestorMoved(javax.swing.event.AncestorEvent)
258: */
259: public void ancestorMoved(AncestorEvent event) {
260: if (calendario != null && this .isShowing() && this .isEnabled()
261: && calendario.isAbilitado())
262: if (Toolkit.getDefaultToolkit().getScreenSize().getHeight()
263: - getLocationOnScreen().getY() - getHeight() < calendario
264: .getSize().getHeight())
265: calendario
266: .setLocation(
267: (int) getLocationOnScreen().getX(),
268: (int) (getLocationOnScreen().getY() - calendario
269: .getSize().getHeight()));
270: else
271: calendario.setLocation((int) getLocationOnScreen()
272: .getX(), (int) getLocationOnScreen().getY()
273: + getHeight());
274: }
275:
276: /**
277: * @see javax.swing.event.AncestorListener#ancestorRemoved(javax.swing.event.AncestorEvent)
278: */
279: public void ancestorRemoved(AncestorEvent event) {
280: if (calendario != null) {
281: calendario.setVisible(false);
282: calendario.setAbilitado(false);
283: calendario.setTextComponent(null);
284: }
285: }
286:
287: /**
288: * Adiciona um listener da lista de listeners do calendário
289: * @param l Listener que vai ouvir quando a calendário for acionado
290: */
291: public void addActionListener(ActionListener l) {
292: listeners.add(ActionListener.class, l);
293: }
294:
295: /**
296: * Remove um listener da lista de listeners do calendário
297: *
298: * @param l listener a ser removido
299: */
300: public void removeActionListener(ActionListener l) {
301: listeners.remove(ActionListener.class, l);
302: }
303:
304: private void fireDataAlterada() {
305: Object[] listeners = this .listeners
306: .getListeners(ActionListener.class);
307:
308: for (int i = 0; i < listeners.length; i++)
309: ((ActionListener) listeners[i])
310: .actionPerformed(new ActionEvent(this , 0, ""));
311: }
312:
313: /**
314: * @see java.awt.Component#requestFocus()
315: */
316: @Override
317: public void requestFocus() {
318: text.requestFocus();
319: }
320:
321: /**
322: * @see java.awt.Component#requestFocus(boolean)
323: */
324: @Override
325: public boolean requestFocus(boolean temporary) {
326: return text.requestFocus(temporary);
327: }
328:
329: /**
330: * @param selectionEnd
331: */
332: public void setSelectionEnd(int selectionEnd) {
333: text.setSelectionEnd(selectionEnd);
334: }
335:
336: /**
337: * @param selectionStart
338: */
339: public void setSelectionStart(int selectionStart) {
340: text.setSelectionStart(selectionStart);
341: }
342:
343: /**
344: * Seta um tooltip para este componente
345: * @see javax.swing.JComponent#setToolTipText(java.lang.String)
346: */
347: @Override
348: public void setToolTipText(String texto) {
349: super .setToolTipText(texto);
350: text.setToolTipText(texto);
351: change.setToolTipText(texto);
352: }
353:
354: /***********************************************************************************************************************************************************
355: * Calsse interna respossável por tratar o evento de clique do JButton do componente.
356: **********************************************************************************************************************************************************/
357: private class InnerAction implements ActionListener {
358:
359: /**
360: * Trata o evento de clique do JButton interno do componente.
361: *
362: * @param e
363: */
364: public void actionPerformed(ActionEvent e) {
365: if (e.getSource() == change) {
366: if (calendario == null) {
367: calendario = new ZCalendarWindow(null);
368: }
369: calendario.setTextComponent(ZCalendarTextField.this );
370: try {
371: calendario
372: .setDate((Date) (new DateFormatter(format))
373: .stringToValue(text.getText()));
374: } catch (ParseException pe) {
375: calendario.setDate(new Date());
376: //TODO Excecao
377: //pe.printStackTrace();
378: }
379:
380: if (Toolkit.getDefaultToolkit().getScreenSize()
381: .getHeight()
382: - getLocationOnScreen().getY() - getHeight() < calendario
383: .getSize().getHeight())
384: calendario
385: .setLocation(
386: (int) getLocationOnScreen().getX(),
387: (int) (getLocationOnScreen().getY() - calendario
388: .getSize().getHeight()));
389: else
390: calendario.setLocation((int) getLocationOnScreen()
391: .getX(), (int) getLocationOnScreen().getY()
392: + getHeight());
393: calendario.setVisible(true);
394: calendario.setAbilitado(true);
395: }
396: }
397: }
398:
399: public Object getRequiredValue() {
400: return getDate();
401: }
402:
403: /*
404: * @see java.awt.Component#removeFocusListener(java.awt.event.FocusListener)
405: */
406: @Override
407: public synchronized void addFocusListener(FocusListener l) {
408: if (text == null | change == null)
409: return;
410: text.addFocusListener(l);
411: change.addFocusListener(l);
412: }
413:
414: /*
415: * @see java.awt.Component#removeFocusListener(java.awt.event.FocusListener)
416: */
417: @Override
418: public synchronized void removeFocusListener(FocusListener l) {
419: text.removeFocusListener(l);
420: change.removeFocusListener(l);
421: }
422:
423: @Override
424: public void setBackground(Color c) {
425: if (text != null)
426: text.setBackground(c);
427: }
428:
429: @Override
430: public Color getBackground() {
431: if (text != null)
432: return text.getBackground();
433: return Color.WHITE;
434: }
435:
436: /*
437: * @see br.com.igor.beans.RequiredField#isSameComponent(java.awt.Component)
438: */
439: public boolean isSameComponent(Component c) {
440: return text == c || change == c || calendario == c;
441: }
442: }
|