Package net.sourceforge.squirrel_sql.fw.completion

Source Code of net.sourceforge.squirrel_sql.fw.completion.Completor

/*
* Copyright (C) 2003 Gerd Wagner
*
* 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; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package net.sourceforge.squirrel_sql.fw.completion;




import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;

public class Completor
{
   public static final Color DEFAULT_POP_UP_BACK_GROUND = new Color(255,255,204);


  private Vector<CompletorListener> _listeners = new Vector<CompletorListener>();
  private ICompletorModel _model;
  private JPanel _completionPanel;
  private JList _completionList;

  private Rectangle _curCompletionPanelSize;
  private PopupManager _popupMan;
  private TextComponentProvider _txtComp;
  private CompletionFocusHandler _completionFocusHandler;
  private FocusListener _completionFocusListener;

  private MouseAdapter _listMouseAdapter;
  private KeyListener _filterKeyListener;
  private static final int MAX_ITEMS_IN_COMPLETION_LIST = 10;
  private JScrollPane _completionListScrollPane;

   private CompletionCandidates _currCandidates;

  private KeyStroke[] _keysToDisableWhenPopUpOpen = new KeyStroke[]
  {
    KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, false),
    KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_MASK, false)
  };

   private Action[] _originalActions = null;

   public Completor(JTextComponent txtComp, ICompletorModel model)
  {
    this(txtComp, model, DEFAULT_POP_UP_BACK_GROUND, false, txtComp); // light yellow
  }

   public Completor(JTextComponent txtComp, ICompletorModel model, Color popUpBackGround, boolean useOwnFilterTextField)
  {
      this(txtComp, model, popUpBackGround, useOwnFilterTextField, txtComp);
   }

   public Completor(JTextComponent txtComp, ICompletorModel model, Color popUpBackGround, boolean useOwnFilterTextField, JComponent popupParent)
  {
      _txtComp = new TextComponentProvider(txtComp, useOwnFilterTextField);

    _model = model;

    _completionPanel =
      new JPanel(new BorderLayout())
      {
                private static final long serialVersionUID = 1L;

                public void setSize(int width, int height)
        {
          // without this the completion panel's size will be weird
          super.setSize(_curCompletionPanelSize.width, _curCompletionPanelSize.height);
        }
      };

    _completionList = new JList(new DefaultListModel());
    _completionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    _completionList.setBackground(popUpBackGround);

    _completionFocusHandler = new CompletionFocusHandler(_txtComp, _completionList);
    _completionFocusListener = new FocusAdapter()
    {
      public void focusLost(FocusEvent e){closePopup();}
    };


    _listMouseAdapter =
      new MouseAdapter()
      {
        public void mouseClicked(MouseEvent e)  {onMousClicked(e);}
      };

    _filterKeyListener =
      new KeyAdapter()
      {
        public void keyPressed(KeyEvent e){onKeyPressedOnList(e);}
      };

    _completionListScrollPane = new JScrollPane(_completionList);

      if(_txtComp.editorEqualsFilter())
      {
       _completionPanel.add(_completionListScrollPane, BorderLayout.CENTER);
      }
      else
      {
         _completionPanel.add(_txtComp.getFilter(), BorderLayout.NORTH);
         _completionPanel.add(_completionListScrollPane, BorderLayout.CENTER);
      }

    _completionPanel.setVisible(false);

      _popupMan = new PopupManager(popupParent);
   }

   private void onKeyPressedOnList(KeyEvent e)
  {
    if(e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_SPACE || e.getKeyCode() == KeyEvent.VK_TAB)
    {
      completionSelected(e.getKeyCode(), e.getModifiers());
    }
      else if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
    {
      closePopup();
    }
    else if(e.getKeyCode() == KeyEvent.VK_BACK_SPACE)
    {
      if(_txtComp.editorEqualsFilter() && 1 >= _currCandidates.getStringToReplace().length())
      {
        closePopup();
      }
      else
      {
        reInitList();
      }
    }
    else if(e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_TAB)
    {
      // do nothing
    }
    else if(e.getKeyCode() == KeyEvent.VK_UP)
    {
      if(0 < _completionList.getSelectedIndex())
      {
        int newSelIx = _completionList.getSelectedIndex() - 1;
        _completionList.setSelectionInterval(newSelIx, newSelIx);
        _completionList.ensureIndexIsVisible(newSelIx);
      }
         else
         {
            int lastIx = _completionList.getModel().getSize() - 1;
            _completionList.setSelectionInterval(lastIx, lastIx);
            _completionList.ensureIndexIsVisible(lastIx);
         }
    }
    else if(e.getKeyCode() == KeyEvent.VK_DOWN)
    {
      if(_completionList.getSelectedIndex() + 1 < _completionList.getModel().getSize())
      {
        int newSelIx = _completionList.getSelectedIndex() + 1;
        _completionList.setSelectionInterval(newSelIx, newSelIx);
        _completionList.ensureIndexIsVisible(newSelIx);
      }
         else
         {
            _completionList.setSelectionInterval(0, 0);
            _completionList.ensureIndexIsVisible(0);
         }
      }
      else if(e.getKeyCode() == KeyEvent.VK_PAGE_UP)
      {
         if(0 < _completionList.getSelectedIndex() - MAX_ITEMS_IN_COMPLETION_LIST)
         {
            int newSelIx = _completionList.getSelectedIndex() - MAX_ITEMS_IN_COMPLETION_LIST;
            _completionList.setSelectionInterval(newSelIx, newSelIx);
            _completionList.ensureIndexIsVisible(newSelIx);
         }
         else
         {
            _completionList.setSelectionInterval(0, 0);
            _completionList.ensureIndexIsVisible(0);
         }
      }
      else if(e.getKeyCode() == KeyEvent.VK_PAGE_DOWN)
      {
         if(_completionList.getSelectedIndex() + MAX_ITEMS_IN_COMPLETION_LIST < _completionList.getModel().getSize())
         {
            int newSelIx = _completionList.getSelectedIndex() + MAX_ITEMS_IN_COMPLETION_LIST;
            _completionList.setSelectionInterval(newSelIx, newSelIx);
            _completionList.ensureIndexIsVisible(newSelIx);
         }
         else
         {
            int lastIndex = _completionList.getModel().getSize() - 1;
            _completionList.setSelectionInterval(lastIndex, lastIndex);
            _completionList.ensureIndexIsVisible(lastIndex);
         }

      }
    else
    {
      reInitList();

      DefaultListModel listModel = (DefaultListModel) _completionList.getModel();
      if(1 == listModel.size())
      {
        CompletionInfo info = (CompletionInfo) listModel.getElementAt(0);
        if(_txtComp.editorEqualsFilter() && _currCandidates.getStringToReplace().toUpperCase().startsWith(info.getCompareString().toUpperCase()))
        {
          closePopup();
        }
      }
    }
  }

  private void reInitList()
  {
      SwingUtilities.invokeLater(new Runnable()
      {
         public void run()
         {
            // Needs to be done later because when reInitList is called,
            // the text componetes model is not yet up to date.
            // E.g. the last character is missing.
            reInitListLater();
         }
      });
  }

   private void reInitListLater()
   {
      _currCandidates = _model.getCompletionCandidates(getTextTillCarret());

      if(0 == _currCandidates.getCandidates().length && _txtComp.editorEqualsFilter())
      {
         closePopup();
      }
      else
      {
         fillAndShowCompletionList(_currCandidates.getCandidates());
      }
   }

   /**
    *
    * @return If there is an extra filter text field the complete text in this text field is returned
    * @throws BadLocationException
    */
   public String getTextTillCarret()
   {
      try
      {
         if(_txtComp.editorEqualsFilter())
      {
         return _txtComp.getEditor().getText(0, _txtComp.getFilter().getCaretPosition());
         }
         else
         {
            return _txtComp.getFilter().getText();
         }
      }
      catch (BadLocationException e)
      {
         throw new RuntimeException(e);
      }
   }

   private void onMousClicked(MouseEvent e)
  {
    if(2 == e.getClickCount())
    {
      completionSelected(KeyEvent.VK_ENTER, 0);
    }
  }

  private void completionSelected(int keyCode, int modifiers)
  {
      Object selected = null;
      if(0 < _completionList.getModel().getSize())
      {
         selected = _completionList.getSelectedValue();
      }
      closePopup();
    if(null != selected && selected instanceof CompletionInfo)
    {
      fireEvent((CompletionInfo)selected, keyCode, modifiers);
    }
  }

  private void closePopup()
  {
    _completionList.removeMouseListener(_listMouseAdapter);
    _txtComp.getFilter().removeKeyListener(_filterKeyListener);
    _completionFocusHandler.setFocusListener(null);

    _completionPanel.setVisible(false);

      if(_txtComp.editorEqualsFilter())
      {
         SwingUtilities.invokeLater(new Runnable()
         {
            public void run()
            {
               Keymap km = _txtComp.getEditor().getKeymap();
               for (int i = 0; i < _keysToDisableWhenPopUpOpen.length; i++)
               {
                  km.removeKeyStrokeBinding(_keysToDisableWhenPopUpOpen[i]);

                  if(null != _originalActions[i])
                  {
                     km.addActionForKeyStroke(_keysToDisableWhenPopUpOpen[i], _originalActions[i]);
                  }
               }
            }
         });
      }
      else
      {
         _txtComp.getFilter().setText("");
         _txtComp.getEditor().requestFocusInWindow();
      }
  }


  public void show()
  {
    try
    {
      _currCandidates = _model.getCompletionCandidates(getTextTillCarret());

      if(0 == _currCandidates.getCandidates().length)
      {
        return;
      }
      if(1 == _currCandidates.getCandidates().length)
      {
        fireEvent(_currCandidates.getCandidates()[0], KeyEvent.VK_ENTER, 0);
        return;
      }

         _txtComp.getEditor().modelToView(_currCandidates.getReplacementStart());

      _completionList.setFont(_txtComp.getEditor().getFont());
      fillAndShowCompletionList(_currCandidates.getCandidates());
    }
    catch (BadLocationException e)
    {
      throw new RuntimeException(e);
    }
  }

   private void fillAndShowCompletionList(CompletionInfo[] candidates)
  {
      try
      {
         // needed to resize completion panle appropriately
         // see initializationof _curCompletionPanelSize
         _curCompletionPanelSize = getCurCompletionPanelSize(candidates);

         DefaultListModel model = (DefaultListModel) _completionList.getModel();
         model.removeAllElements();

         for (int i = 0; i < candidates.length; i++)
         {
            model.addElement(candidates[i]);
         }

         Rectangle caretBounds;
         if(_txtComp.editorEqualsFilter())
         {
            caretBounds = _txtComp.getEditor().modelToView(_currCandidates.getReplacementStart());
         }
         else
         {
            caretBounds = _txtComp.getEditor().modelToView(_txtComp.getEditor().getCaretPosition());
         }

         _popupMan.install(_completionPanel, caretBounds, PopupManager.BelowPreferred);

         _completionList.setSelectedIndex(0);
         _completionList.ensureIndexIsVisible(0);
         _completionPanel.setVisible(true);

         _completionList.removeMouseListener(_listMouseAdapter);
         _completionList.addMouseListener(_listMouseAdapter);
         _txtComp.getFilter().removeKeyListener(_filterKeyListener);
         _txtComp.getFilter().addKeyListener(_filterKeyListener);

      _completionFocusHandler.setFocusListener(_completionFocusListener);


      if(_txtComp.editorEqualsFilter())
      {
          Action doNothingAction = new AbstractAction("doNothingAction")
          {
              private static final long serialVersionUID = 1L;

              public void actionPerformed(ActionEvent e)
              {
              }
          };

            Keymap km = _txtComp.getEditor().getKeymap();

            if(null == _originalActions)
            {
               _originalActions = new Action[_keysToDisableWhenPopUpOpen.length];

               for (int i = 0; i < _keysToDisableWhenPopUpOpen.length; i++)
               {
                  _originalActions[i] = km.getAction(_keysToDisableWhenPopUpOpen[i]);
               }
            }

            for (int i = 0; i < _keysToDisableWhenPopUpOpen.length; i++)
            {
               km.addActionForKeyStroke(_keysToDisableWhenPopUpOpen[i], doNothingAction);
            }
         }
         else
         {
            _txtComp.getFilter().requestFocusInWindow();
         }
      }
      catch (BadLocationException e)
      {
         throw new RuntimeException(e);
      }
   }


  private Rectangle getCurCompletionPanelSize(CompletionInfo[] candidates)
  {
    FontMetrics fm = _txtComp.getEditor().getGraphics().getFontMetrics(_txtComp.getEditor().getFont());
    int width = getCurCompletionPanelWidth(candidates, fm) + 32;
    int height = (int)(Math.min(candidates.length,  MAX_ITEMS_IN_COMPLETION_LIST) * (fm.getHeight() + 2.3) + 3);


      if(false == _txtComp.editorEqualsFilter())
      {
         height += _txtComp.getFilter().getPreferredSize().getHeight();
      }

    return new Rectangle(width, height);
  }

  private int getCurCompletionPanelWidth(CompletionInfo[] infos, FontMetrics fontMetrics)
  {
      int maxSize = 0;
      if(false == _txtComp.editorEqualsFilter() && null != _txtComp.getFilter().getText())
      {
         maxSize = Math.max(fontMetrics.stringWidth(_txtComp.getFilter().getText() + "   "), maxSize);
      }

    for (int i = 0; i < infos.length; i++)
    {
         maxSize = Math.max(fontMetrics.stringWidth(infos[i].toString()), maxSize);
    }
    return maxSize;

  }


  private void fireEvent(CompletionInfo completion, int keyCode, int modifiers)
  {
    Vector<CompletorListener> clone = new Vector<CompletorListener>(_listeners);

    for (int i = 0; i < clone.size(); i++)
    {
         CompletorListener completorListener = clone.elementAt(i);
         if(_txtComp.editorEqualsFilter())
         {
            completorListener.completionSelected(completion, _currCandidates.getReplacementStart(), keyCode, modifiers);
         }
         else
         {
            completorListener.completionSelected(completion, -1, keyCode, modifiers);
         }
    }
  }

  public void addCodeCompletorListener(CompletorListener l)
  {
    _listeners.add(l);
  }

  public void removeCodeCompletorListener(CompletorListener l)
  {
    _listeners.remove(l);
  }

}
TOP

Related Classes of net.sourceforge.squirrel_sql.fw.completion.Completor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.