⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 abstractblockfield.java

📁 Rapla是一个灵活的多用户资源管理系统。它提供的一些功能有:日历GUI
💻 JAVA
字号:
/*--------------------------------------------------------------------------*
 | Copyright (C) 2006 Christopher Kohlhaas                                  |
 |                                                                          |
 | This program is free software; you can redistribute it and/or modify     |
 | it under the terms of the GNU General Public License as published by the |
 | Free Software Foundation. A copy of the license has been included with   |
 | these distribution in the COPYING file, if not go to www.fsf.org         |
 |                                                                          |
 | As a special exception, you are granted the permissions to link this     |
 | program with every library, which license fulfills the Open Source       |
 | Definition as published by the Open Source Initiative (OSI).             |
 *--------------------------------------------------------------------------*/
package org.rapla.components.calendar;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

import java.util.ArrayList;
import java.awt.*;
import java.awt.event.*;
import java.util.Observable;
import java.util.Observer;

import org.rapla.components.calendar.jdk14adapter.AWTAdapterFactory;

/** The base class for TextFields that supports entering values in
    blocks. Most notifiably the DateField and the TimeField. <br> You
    can use the left/right arrow keys to switch the blocks. Use of the
    top/down arrow keys will increase/decrease the values in the
    selected block (page_up/page_down for major changes). You can
    specify maximum length for each block. If a block reaches this
    maximum value the focus will switch to the next block.
    @see DateField
    @see TimeField
 */
public abstract class AbstractBlockField extends JTextField {
    int m_markedBlock = 0;
    char m_lastChar = 0;
    boolean m_keyPressed = false;
    protected String m_oldText;

    ArrayList m_listenerList = new ArrayList();

    public AbstractBlockField() {
        Listener listener = new Listener();
        addMouseListener(listener);
        addActionListener(listener);
        addFocusListener(listener);
        addKeyListener(listener);
        AWTAdapterFactory fact = AWTAdapterFactory.getFactory();
        if (fact != null)
            fact.createMouseWheelObservable(this).addObserver(listener);
    }

    class Listener implements MouseListener,KeyListener,FocusListener,Observer,ActionListener {
        public void mouseReleased(MouseEvent evt) {
        }
        public void mousePressed(MouseEvent evt) {
            // We have to mark the block on mouse pressed and mouse clicked.
            // Windows needs mouse clicked while Linux needs mouse pressed.
            markCurrentBlock();
        }
        public void mouseEntered(MouseEvent me) {
        }
        public void mouseExited(MouseEvent me) {
        }
        public void mouseClicked(MouseEvent evt) {
            // We have to mark the block on mouse pressed and mouse clicked.
            markCurrentBlock();
            if (evt.getClickCount()>1) {
                selectAll();
                return;
            }
            if (blocksValid()) {
                fireValueChanged();
            }
        }

        // Implementation of ActionListener
        public void actionPerformed(ActionEvent e) {
            blocksValid();
            fireValueChanged();
        }

        public void focusGained(FocusEvent evt) {
            if (blocksValid()) {
                setBlock(0);
            }
        }
        public void focusLost(FocusEvent evt) {
            select(-1,-1);
            blocksValid();
            fireValueChanged();
        }

        public void keyPressed(KeyEvent evt) {
            m_keyPressed = true;
            m_lastChar=evt.getKeyChar();
            if (!blocksValid())
                return;
            if (isSeparator(evt.getKeyChar())) {
                evt.consume();
                return;
            }
            switch (evt.getKeyCode()) {
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_KP_LEFT:
                if (blockCount() >1) {
                    setBlock(-1);
                    evt.consume();
                }
                return;
            case KeyEvent.VK_KP_RIGHT:
            case KeyEvent.VK_RIGHT:
                if (blockCount() >1) {
                    setBlock(1);
                    evt.consume();
                }
                return;
            case KeyEvent.VK_HOME:
                setBlock(-1000);
                evt.consume();
                return;
            case KeyEvent.VK_END:
                setBlock(1000);
                evt.consume();
                return;
            case KeyEvent.VK_KP_UP:
            case KeyEvent.VK_UP:
                changeSelectedBlock(1);
                evt.consume();
                return;
            case KeyEvent.VK_KP_DOWN:
            case KeyEvent.VK_DOWN:
                changeSelectedBlock(-1);
                evt.consume();
                        return;
            case KeyEvent.VK_PAGE_UP:
                changeSelectedBlock(10);
                evt.consume();
                return;
            case KeyEvent.VK_PAGE_DOWN:
                changeSelectedBlock(-10);
                evt.consume();
                return;
            }
        }

        public void keyReleased(KeyEvent evt) {
            m_lastChar=evt.getKeyChar();
            // Only change the block if the keyReleased
            // event follows a keyPressed.
            // If you type very quickly you could
            // get two strunged keyReleased events
            if (m_keyPressed == true)
                m_keyPressed = false;
            else
                        return;
            if (!blocksValid())
                return;
            if (isSeparator(m_lastChar) ) {
                if ( isSeparator( getText().charAt(getCaretPosition())))
                    nextBlock();
                evt.consume();
            } else if (isValidChar(m_lastChar)) {
                advance();
                evt.consume();
            }
        }
        public void keyTyped(KeyEvent evt) {
        }
        /** MouseWheelObserver */
        public void update(Observable o, Object arg) {
            if (!blocksValid() || arg == null)
                return;
            int count = ((Long) arg).intValue();
            changeSelectedBlock(-1 * count/(Math.abs(count)));
        }
    }

    private void markCurrentBlock() {
        if (!blocksValid()) {
            return;
        }
        int blockstart[] = new int[blockCount()];
        int block = calcBlocks(blockstart);
        markBlock(blockstart,block);
    }

    public void addChangeListener(ChangeListener listener) {
        m_listenerList.add(listener);
    }

    /** removes a listener from this component.*/
    public void removeChangeListener(ChangeListener listener) {
        m_listenerList.remove(listener);
    }

    public ChangeListener[] getChangeListeners() {
        return (ChangeListener[])m_listenerList.toArray(new ChangeListener[]{});
    }

    /** A ChangeEvent will be fired to every registered ActionListener
     *  when the value has changed.
    */
    protected void fireValueChanged() {
        if (m_listenerList.size() == 0)
            return;

        // Only fire, when text has changed.
        if (m_oldText != null && m_oldText.equals(getText()))
            return;
        m_oldText = getText();

        ChangeEvent evt = new ChangeEvent(this);
        ChangeListener[] listeners = getChangeListeners();
        for (int i = 0; i<listeners.length; i ++) {
            listeners[i].stateChanged(evt);
        }
    }
    

    //  switch to next block
    private void nextBlock() {
        int[] blockstart = new int[blockCount()];
        int block = calcBlocks(blockstart);
        markBlock(blockstart,Math.min(block + 1,blockCount() -1));
    }

    //  switch to next block if blockend is reached and
    private void advance() {
        if (blockCount()<2)
            return;
        int blockstart[] = new int[blockCount()];
        int block = calcBlocks(blockstart);
        if (block >= blockCount() -1)
            return;
        int selectedLen = (block ==0) ? blockstart[1] : (blockstart[block + 1] - blockstart[block] - 1);
        if (selectedLen == maxBlockLength(block)) {
            markBlock(blockstart,Math.min(block + 1,blockCount() -1));
        }
    }

    /**  changes the value of the selected Block. Adds the count value. */
    private void changeSelectedBlock(int count) {
        int blockstart[] = new int[blockCount()];
        int block = calcBlocks(blockstart);
        int start = (block == 0) ? 0 : blockstart[block] + 1;
        int end = (block == blockCount() -1) ? getText().length() : blockstart[block+1];
        String selected = getText().substring(start,end);
        markBlock(blockstart,block);
        changeSelectedBlock(blockstart,block,selected,count);
    }

    private void setBlock(int count) {
        if (blockCount()<1)
            return;
        int blockstart[] = new int[blockCount()];
        int block = calcBlocks(blockstart);
        if (count !=0)
            markBlock(blockstart,Math.min(Math.max(0,block + count),blockCount()-1));
        else
            markBlock(blockstart,m_markedBlock);
    }


    /** Select the specified block. */
    final protected void markBlock(int[] blockstart,int block) {
        m_markedBlock = block;
        if (m_markedBlock == 0)
            mark(blockstart[0], (blockCount()>1) ? blockstart[1] : getText().length());
        else if (m_markedBlock==blockCount()-1)
            mark(blockstart[m_markedBlock] + 1,getText().length());
        else
            mark(blockstart[m_markedBlock] + 1,blockstart[m_markedBlock+1]);
    }

    private boolean isPrevSeparator(int i,char[] source,String currentText,int offs) {
        return (i>0 && isSeparator(source[i-1])
            || (offs > 0 && isSeparator(currentText.charAt(offs-1))));
    }
    private boolean isNextSeparator(int i,char[] source,String currentText,int offs) {
        return (offs < currentText.length()-1 && isSeparator(currentText.charAt(offs)));
    }

    class DateDocument extends PlainDocument {
        private static final long serialVersionUID = 1L;

        public void insertString(int offs, String str, AttributeSet a)
                        throws BadLocationException {
            String currentText = getText(0, getLength());
            char[] source = str.toCharArray();
            char[] result = new char[source.length];
            int j = 0;
            boolean bShouldBeep = false;
            for (int i = 0; i < source.length; i++) {
                boolean bValid = true;
                if (!isValidChar(source[i])) {
                    bValid = false;
                } else {
                    //if (offs < currentText.length()-1)
                    //System.out.println("offset-char: " + currentText.charAt(offs));
//
                    if (isSeparator(source[i]))
                        if (isNextSeparator(i,source,currentText,offs)
                            || isPrevSeparator(i,source,currentText,offs)
                            || (i==0 && offs==0)
                            || (i==source.length && offs==currentText.length())
                            )
                        {
                            //                      beep();
                            continue;
                        }
                }
                if (bValid)
                    result[j++] = source[i];
                else
                    bShouldBeep = true;
            }
            if (bShouldBeep)
                beep();
            super.insertString(offs, new String(result, 0, j), a);
        }
        public void remove(int offs, int len)
            throws BadLocationException {
            if (m_lastChar == 0
                || (!isSeparator(m_lastChar)
                    && (isValidChar(m_lastChar)
                        || !Character.isLetter(m_lastChar))
                    )
                )
                super.remove(offs, len);
        }
    }

    final protected Document createDefaultModel() {
        return new DateDocument();
    }

    /** Calculate the blocks. The new blockstarts will be stored in
        the int array.
        @return the block that contains the caret.
    */
    protected int calcBlocks(int[] blockstart) {
        String text = getText();
        int dot = getCaretPosition();
        int block = 0;
        blockstart[0] = 0;
        char[] separators = getSeparators();
        for (int i=1;i<blockstart.length;i++) {
            int min = text.length();
            for (int j=0;j<separators.length;j++) {
                int pos = text.indexOf(separators[j], blockstart[i-1] + 1);
                if (pos>=0 && pos < min)
                    min = pos;
            }
            blockstart[i] = min;
            if (dot>blockstart[i])
                block = i;
        }
        return block;
    }

    /** Select the text from dot to mark. */
    protected void mark(int dot,int mark) {
        setCaretPosition(mark);
        moveCaretPosition(dot);
    }

    /** this method will be called when an non-valid character is entered. */
    protected void beep() {
        Toolkit.getDefaultToolkit().beep();
    }

    /** returns true if the text can be split into blocks. */
    abstract public boolean blocksValid();
    /** The number of blocks for this Component.  */
    abstract protected int blockCount();
    /** This method will be called, when the user has pressed the up/down
     * arrows on a selected block.
     * @param count Posible values are 1,-1,10,-10.
    */
    abstract protected void changeSelectedBlock(int[] blocks,int block,String selected,int count);
    /** returns the maximum length of the specified block.  */
    abstract protected int maxBlockLength(int block);
    /** returns true if the character should be accepted by the component.   */
    abstract protected boolean isValidChar(char c);
    /** returns true if the character is a block-separator. All block-separators must
    be valid characters.
    @see #isValidChar
    */
    abstract protected boolean isSeparator(char c);
    /** @return all seperators.*/
    abstract protected char[] getSeparators();

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -