001: /*
002: * Created on 13/09/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.DecimalFormat;
039: import java.text.NumberFormat;
040: import java.text.ParseException;
041:
042: import javax.swing.JButton;
043: import javax.swing.JFormattedTextField;
044: import javax.swing.JFrame;
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.DefaultFormatterFactory;
050: import javax.swing.text.NumberFormatter;
051:
052: import br.com.gfpshare.beans.aplicativos.IconeFactory;
053:
054: /**
055: * Classe que representa um componente composto de um JFormattedTextField e um JButton, sendo que o JFormattedTextField é responssável por exibir uma String que
056: * 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
057: * ICalendar, o qual exibirá uma forma visual do usuário selecionar uma data. <br>
058: * <br>
059: * Atualmente existem dois componentes que implementam a interface ICalendar. ICalendarFrame e ICalendarWindow, ambos podem ser passados para o contrutor desta
060: * 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.
061: *
062: * @author Igor Regis da Silva Simoes
063: * @created 20/01/2004
064: * @see ICalendar
065: */
066: public class ZMoneyTextField extends JPanel implements Serializable,
067: AncestorListener, RequiredField {
068: /**
069: * Campo de texto que exibe a data e permite edição pelo usuário
070: */
071: private JFormattedTextField text;
072:
073: /**
074: * Botão que aciona o calendario
075: */
076: private JButton change;
077:
078: /**
079: * Calendario que fornece uma forma gráfica de seleção da data
080: */
081: private ZMoneyCalculatorWindow calculadora = null;
082:
083: /**
084: * Componente com o formato da data para exibição em String
085: */
086: private DateFormat format;
087:
088: /**
089: *
090: */
091: private EventListenerList listeners = new EventListenerList();
092:
093: /*
094: * Used only to test this component
095: public static void main(String[] args)
096: {
097: JFrame f = new JFrame();
098: f.getContentPane().setLayout(new GridBagLayout());
099: f.getContentPane().add(new MoneyTextField(f));
100: f.setSize(800,600);
101: f.setVisible(true);
102: }
103: */
104: /**
105: * Cria uma nova instancia de ICalendarTextField, tendo como padrão um ICalendarFrame, para edição visual da data pelo ususário.
106: * @param owner
107: */
108: public ZMoneyTextField(JFrame owner) {
109: setOpaque(false);
110: setLayout(null);
111: text = new JFormattedTextField() {
112: {
113: NumberFormatter mascaraView = new NumberFormatter(
114: NumberFormat.getCurrencyInstance());
115: NumberFormatter mascaraEdicao = new NumberFormatter(
116: new DecimalFormat("#.00"));
117:
118: mascaraView.setAllowsInvalid(false);
119: mascaraView.setValueClass(Double.class);
120:
121: mascaraEdicao.setAllowsInvalid(false);
122: mascaraEdicao.setValueClass(Double.class);
123:
124: setFormatterFactory(new DefaultFormatterFactory(
125: mascaraView, mascaraView, mascaraEdicao));
126: setName("MoneyTextField");
127: }
128:
129: /**
130: * @see javax.swing.text.JTextComponent#setText(java.lang.String)
131: */
132: @Override
133: public void setText(String t) {
134: super .setText(t);
135: if (t.startsWith("-"))
136: setForeground(java.awt.Color.RED);
137: else
138: setForeground(java.awt.Color.BLACK);
139: }
140: };
141:
142: text.addActionListener(new InnerAction());
143: add(text);
144:
145: change = new ViewButton(IconeFactory.getIconeFactory()
146: .getScaledImage("/icones/16x16/xcalc.png", 16), null);
147: change.setOpaque(false);
148: change.addActionListener(new InnerAction());
149: add(change);
150:
151: setName("MoneyTextField");
152: setPreferredSize(new Dimension(100, 26));
153:
154: this .addAncestorListener(this );
155: }
156:
157: public ZMoneyTextField() {
158: this (null);
159: }
160:
161: /**
162: * Determina as medidas do componete e de seus subcomponentes.
163: *
164: * @param x Posição X do componente
165: * @param y Posição Y do componente
166: * @param width Comprimento do componente
167: * @param height Altura do componente
168: */
169: @Override
170: public void setBounds(int x, int y, int width, int height) {
171: super .setBounds(x, y, width, height);
172: text.setBounds(0, 0, width - 22, height);
173: change.setBounds(width - 20, 0, 20, height);
174: }
175:
176: /**
177: * Determina um novo formato para exibição da data pelo componete.
178: *
179: * @param f Configuração do formato
180: */
181: public void setMask(JFormattedTextField.AbstractFormatterFactory f) {
182: text.setFormatterFactory(f);
183: }
184:
185: /**
186: * Retorna o conteúdo do componete (data) em forma de String.
187: *
188: * @return Data
189: */
190: public String getText() {
191: return text.getText();
192: }
193:
194: /**
195: * Atribui uma nova data a ser utilizada pelo componente.
196: *
197: * @param string valor
198: */
199: public void setText(String string) {
200: text.setValue(string);
201: fireDataAlterada();
202: }
203:
204: /**
205: * @param value
206: */
207: public void setValue(Object value) {
208: text.setValue(value);
209: }
210:
211: /**
212: * Retorna o conteúdo do componete (data) em forma de String.
213: *
214: * @return Data
215: */
216: public Object getValue() {
217: try {
218: text.commitEdit();
219: } catch (ParseException e) {
220: //Do nothing
221: }
222: return text.getValue();
223: }
224:
225: /**
226: * Usado para Habilitar e desabilitar o componente
227: *
228: * @param enabled
229: */
230: @Override
231: public void setEnabled(boolean enabled) {
232: text.setEnabled(enabled);
233: change.setEnabled(enabled);
234: }
235:
236: /**
237: * @see javax.swing.event.AncestorListener#ancestorAdded(javax.swing.event.AncestorEvent)
238: */
239: public void ancestorAdded(AncestorEvent event) {
240: if (calculadora != null) {
241: if (isEnabled() && calculadora.isAbilitado()) {
242: calculadora.setVisible(true);
243: calculadora.setTextComponent(text);
244: }
245: }
246: }
247:
248: /**
249: * @see javax.swing.event.AncestorListener#ancestorMoved(javax.swing.event.AncestorEvent)
250: */
251: public void ancestorMoved(AncestorEvent event) {
252: if (calculadora != null && this .isShowing() && this .isEnabled()
253: && calculadora.isAbilitado())
254: if (Toolkit.getDefaultToolkit().getScreenSize().getHeight()
255: - getLocationOnScreen().getY() - getHeight() < calculadora
256: .getSize().getHeight())
257: calculadora
258: .setLocation(
259: (int) getLocationOnScreen().getX(),
260: (int) (getLocationOnScreen().getY() - calculadora
261: .getSize().getHeight()));
262: else
263: calculadora.setLocation((int) getLocationOnScreen()
264: .getX(), (int) getLocationOnScreen().getY()
265: + getHeight());
266: }
267:
268: /**
269: * @see javax.swing.event.AncestorListener#ancestorRemoved(javax.swing.event.AncestorEvent)
270: */
271: public void ancestorRemoved(AncestorEvent event) {
272: if (calculadora != null) {
273: calculadora.setVisible(false);
274: calculadora.setAbilitado(false);
275: calculadora.setTextComponent(null);
276: }
277: }
278:
279: /**
280: * Adiciona um listener da lista de listeners do calendário
281: * @param l Listener que vai ouvir quando a calendário for acionado
282: */
283: public void addActionListener(ActionListener l) {
284: listeners.add(ActionListener.class, l);
285: }
286:
287: /**
288: * Remove um listener da lista de listeners do calendário
289: *
290: * @param l listener a ser removido
291: */
292: public void removeActionListener(ActionListener l) {
293: listeners.remove(ActionListener.class, l);
294: }
295:
296: private void fireDataAlterada() {
297: Object[] listeners = this .listeners
298: .getListeners(ActionListener.class);
299:
300: for (int i = 0; i < listeners.length; i++)
301: ((ActionListener) listeners[i])
302: .actionPerformed(new ActionEvent(this , 0, ""));
303: }
304:
305: /**
306: * @see java.awt.Component#requestFocus()
307: */
308: @Override
309: public void requestFocus() {
310: text.requestFocus();
311: }
312:
313: /**
314: * @see java.awt.Component#requestFocus(boolean)
315: */
316: @Override
317: public boolean requestFocus(boolean temporary) {
318: return text.requestFocus(temporary);
319: }
320:
321: /**
322: * @param selectionEnd
323: */
324: public void setSelectionEnd(int selectionEnd) {
325: text.setSelectionEnd(selectionEnd);
326: }
327:
328: /**
329: * @param selectionStart
330: */
331: public void setSelectionStart(int selectionStart) {
332: text.setSelectionStart(selectionStart);
333: }
334:
335: /**
336: * Seta um tooltip para este componente
337: * @see javax.swing.JComponent#setToolTipText(java.lang.String)
338: */
339: @Override
340: public void setToolTipText(String texto) {
341: super .setToolTipText(texto);
342: text.setToolTipText(texto);
343: change.setToolTipText(texto);
344: }
345:
346: /***********************************************************************************************************************************************************
347: * Calsse interna respossável por tratar o evento de clique do JButton do componente.
348: **********************************************************************************************************************************************************/
349: private class InnerAction implements ActionListener {
350:
351: /**
352: * Trata o evento de clique do JButton interno do componente.
353: *
354: * @param e
355: */
356: public void actionPerformed(ActionEvent e) {
357: if (e.getSource() == change) {
358: if (calculadora == null) {
359: calculadora = new ZMoneyCalculatorWindow(null);
360: calculadora.setTextComponent(text);
361: }
362: calculadora.setValue(text.getValue());
363: if (Toolkit.getDefaultToolkit().getScreenSize()
364: .getHeight()
365: - getLocationOnScreen().getY() - getHeight() < calculadora
366: .getSize().getHeight())
367: calculadora
368: .setLocation(
369: (int) getLocationOnScreen().getX(),
370: (int) (getLocationOnScreen().getY() - calculadora
371: .getSize().getHeight()));
372: else
373: calculadora.setLocation((int) getLocationOnScreen()
374: .getX(), (int) getLocationOnScreen().getY()
375: + getHeight());
376: calculadora.setVisible(true);
377: calculadora.setAbilitado(true);
378: }
379: }
380: }
381:
382: /**
383: * Retorna o valor atualmente editado neste campo, caso haja erro no parsing do
384: * valor, (valor invalido) retornamos null
385: */
386: public Object getRequiredValue() {
387: try {
388: text.commitEdit();
389: } catch (ParseException e) {
390: return null;
391: }
392: return getValue();
393: }
394:
395: /*
396: * @see java.awt.Component#removeFocusListener(java.awt.event.FocusListener)
397: */
398: @Override
399: public synchronized void addFocusListener(FocusListener l) {
400: if (text == null || change == null)
401: return;
402: text.addFocusListener(l);
403: change.addFocusListener(l);
404: super .addFocusListener(l);
405: }
406:
407: /*
408: * @see java.awt.Component#removeFocusListener(java.awt.event.FocusListener)
409: */
410: @Override
411: public synchronized void removeFocusListener(FocusListener l) {
412: text.removeFocusListener(l);
413: change.removeFocusListener(l);
414: super .removeFocusListener(l);
415: }
416:
417: @Override
418: public void setBackground(Color c) {
419: if (text != null)
420: text.setBackground(c);
421: }
422:
423: @Override
424: public Color getBackground() {
425: if (text != null)
426: return text.getBackground();
427: return Color.WHITE;
428: }
429:
430: /*
431: * @see br.com.igor.beans.RequiredField#isSameComponent(java.awt.Component)
432: */
433: public boolean isSameComponent(Component c) {
434: return text == c || change == c || calculadora == c;
435: }
436: }
|