/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.plugin.keybindingchooser.globalchooser;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import net.java.sip.communicator.plugin.keybindingchooser.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.plugin.desktoputil.plaf.*;
import net.java.sip.communicator.service.globalshortcut.*;
import net.java.sip.communicator.util.skin.*;
import org.jitsi.util.*;
// disambiguation
/**
* Dialog to choose the shortcut.
*
* @author Sebastien Vincent
*/
public class GlobalShortcutDialog
extends SIPCommDialog
implements ActionListener,
GlobalShortcutListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* Text displayed when no shortcut is configured.
*/
private static final String PRESS_TO_SETUP_SHORTCUT =
Resources.getString("plugin.keybindings.globalchooser.PRESS_BTN");
/**
* The global shortcut entry.
*/
private final GlobalShortcutEntry entry;
/**
* OK button.
*/
private final JButton btnOK = new JButton(
Resources.getString("service.gui.OK"));
/**
* Cancel button.
*/
private final JButton btnCancel = new JButton(
Resources.getString("service.gui.CANCEL"));
/**
* Enable or not special key for shortcut.
*/
private final JCheckBox specialBox = new SIPCommCheckBox(
Resources.getString("plugin.keybindings.globalchooser.ENABLE_SPECIAL"));
/**
* First shortcut field.
*/
private final ShortcutField fldShortcut = new ShortcutField(
PRESS_TO_SETUP_SHORTCUT);
/**
* Secondary shortcut field.
*/
private final ShortcutField fldShortcut2 = new ShortcutField(
PRESS_TO_SETUP_SHORTCUT);
/**
* Return code.
*/
private int retCode = 0;
/**
* Constructor.
*
* @param dialog root dialog
* @param entry the global shortcut entry
*/
public GlobalShortcutDialog(Dialog dialog, GlobalShortcutEntry entry)
{
super(dialog);
setModal(true);
setTitle("Global shortcut: " + entry.getAction());
this.entry = entry;
init();
}
/**
* Initialize components.
*/
private void init()
{
TransparentPanel mainPanel = new TransparentPanel(new BorderLayout());
JPanel btnPanel = new TransparentPanel(
new FlowLayout(FlowLayout.RIGHT));
JPanel shortcutPanel = new TransparentPanel(
new GridLayout(0, 2, 0, 10));
btnOK.addActionListener(this);
btnCancel.addActionListener(this);
KeyAdapter keyAdapter = new KeyAdapter()
{
private KeyEvent buffer = null;
@Override
public void keyPressed(KeyEvent event)
{
if(event.getKeyCode() == KeyEvent.VK_ESCAPE)
{
SIPCommTextField field =
(SIPCommTextField)event.getSource();
AWTKeyStroke ks = null;
if(field == fldShortcut)
{
ks = entry.getShortcut();
}
else if(field == fldShortcut2)
{
ks = entry.getShortcut2();
}
if(ks == null)
field.setText(PRESS_TO_SETUP_SHORTCUT);
else
{
if(ks.getModifiers() ==
GlobalShortcutService.SPECIAL_KEY_MODIFIERS)
{
field.setText("Special");
}
else
{
field.setText(GlobalShortcutEntry.getShortcutText(
entry.getShortcut()));
}
}
btnOK.requestFocusInWindow();
return;
}
if(event.getKeyCode() == 0)
return;
// Reports KEY_PRESSED events on release to support modifiers
this.buffer = event;
}
@Override
public void keyReleased(KeyEvent event)
{
if (buffer != null)
{
SIPCommTextField field =
(SIPCommTextField)event.getSource();
AWTKeyStroke input = KeyStroke.getKeyStrokeForEvent(buffer);
buffer = null;
GlobalShortcutEntry en = entry;
List<AWTKeyStroke> kss = new ArrayList<AWTKeyStroke>();
if(field == fldShortcut)
{
kss.add(input);
kss.add(en.getShortcut2());
}
else if(field == fldShortcut2)
{
kss.add(en.getShortcut());
kss.add(input);
}
en.setShortcuts(kss);
en.setEditShortcut1(false);
en.setEditShortcut2(false);
field.setText(GlobalShortcutEntry.getShortcutText(
input));
btnOK.requestFocus();
}
}
};
AWTKeyStroke ks = entry.getShortcut();
AWTKeyStroke ks2 = entry.getShortcut2();
if(ks != null)
{
if(ks.getModifiers() != GlobalShortcutService.SPECIAL_KEY_MODIFIERS)
{
fldShortcut.setText(GlobalShortcutEntry.getShortcutText(ks));
}
else
{
fldShortcut.setText("Special");
}
}
if(ks2 != null)
{
if(ks2.getModifiers() != GlobalShortcutService.SPECIAL_KEY_MODIFIERS)
{
fldShortcut2.setText(GlobalShortcutEntry.getShortcutText(ks2));
}
else
{
fldShortcut2.setText("Special");
}
}
fldShortcut.addKeyListener(keyAdapter);
fldShortcut2.addKeyListener(keyAdapter);
specialBox.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent evt)
{
KeybindingChooserActivator.getGlobalShortcutService().
setSpecialKeyDetection(
(evt.getStateChange() == ItemEvent.SELECTED),
GlobalShortcutDialog.this);
}
});
shortcutPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10,
10));
shortcutPanel.add(new JLabel("Primary shortcut"));
shortcutPanel.add(fldShortcut);
shortcutPanel.add(new JLabel("Secondary shortcut"));
shortcutPanel.add(fldShortcut2);
if(OSUtils.IS_WINDOWS)
{
shortcutPanel.add(new TransparentPanel());
shortcutPanel.add(specialBox);
}
mainPanel.add(shortcutPanel, BorderLayout.CENTER);
btnPanel.add(btnOK);
btnPanel.add(btnCancel);
mainPanel.add(btnPanel, BorderLayout.SOUTH);
btnOK.requestFocus();
getContentPane().add(mainPanel);
pack();
}
/**
* {@inheritDoc}
*/
@Override
protected void close(boolean isEscaped)
{
super.close(isEscaped);
KeybindingChooserActivator.getGlobalShortcutService().
setSpecialKeyDetection(false, this);
}
/**
* Show the dialog and returns if the user has modified something (create
* or modify entry).
*
* @return true if the user has modified something (create
* or modify entry), false otherwise.
*/
public int showDialog()
{
setVisible(true);
// as the dialog is modal, wait for OK/Cancel button retCode
setVisible(false);
return retCode;
}
/**
* {@inheritDoc}
*/
public void actionPerformed(ActionEvent evt)
{
Object obj = evt.getSource();
if(obj == btnOK)
{
retCode = 1;
dispose();
}
else if(obj == btnCancel)
{
retCode = 0;
dispose();
}
}
/**
* {@inheritDoc}
*/
public void shortcutReceived(GlobalShortcutEvent evt)
{
AWTKeyStroke ksr = evt.getKeyStroke();
if(ksr.getModifiers() != GlobalShortcutService.SPECIAL_KEY_MODIFIERS)
{
return;
}
if(!fldShortcut.isFocusOwner() && !fldShortcut2.isFocusOwner())
return;
List<AWTKeyStroke> kss = new ArrayList<AWTKeyStroke>();
if(fldShortcut.isFocusOwner())
{
kss.add(ksr);
kss.add(entry.getShortcut2());
fldShortcut.setText("Special");
}
else if(fldShortcut2.isFocusOwner())
{
kss.add(entry.getShortcut());
kss.add(ksr);
fldShortcut2.setText("Special");
}
entry.setShortcuts(kss);
KeybindingChooserActivator.getGlobalShortcutService().
setSpecialKeyDetection(false, this);
}
/**
* Clear the text field.
*
* @param ui <tt>TextFieldUI</tt> to clear
*/
public void clearTextField(SIPCommTextFieldUI ui)
{
List<AWTKeyStroke> kss = new ArrayList<AWTKeyStroke>();
if(ui == fldShortcut.getUI())
{
kss.add(null);
kss.add(entry.getShortcut2());
entry.setShortcuts(kss);
btnOK.requestFocusInWindow();
}
else if(ui == fldShortcut2.getUI())
{
kss.add(entry.getShortcut());
kss.add(null);
entry.setShortcuts(kss);
btnOK.requestFocusInWindow();
}
}
/**
* A custom call field.
*/
private class ShortcutField
extends SIPCommTextField
implements Skinnable
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The text field ui.
*/
private ShortcutFieldUI textFieldUI;
/**
* Creates an instance of the <tt>CallField</tt>.
*
* @param text
*/
public ShortcutField(String text)
{
super(text);
textFieldUI = new ShortcutFieldUI();
textFieldUI.setDeleteButtonEnabled(true);
this.setPreferredSize(new Dimension(200, 23));
this.setUI(textFieldUI);
this.setBorder(BorderFactory.createEmptyBorder(0, 8, 0, 8));
this.setOpaque(false);
this.setDragEnabled(true);
loadSkin();
}
/**
* Reloads text field UI defs.
*/
public void loadSkin()
{
textFieldUI.loadSkin();
}
}
/**
* A custom text field UI.
*/
public class ShortcutFieldUI
extends SIPCommTextFieldUI
implements Skinnable
{
/**
* Creates a <tt>SIPCommTextFieldUI</tt>.
*/
public ShortcutFieldUI()
{
loadSkin();
}
/**
* Adds the custom mouse listeners defined in this class to the installed
* listeners.
*/
@Override
protected void installListeners()
{
super.installListeners();
}
/**
* {@inheritDoc}
*/
@Override
protected void updateDeleteIcon(MouseEvent evt)
{
super.updateDeleteIcon(evt);
Rectangle deleteRect = getDeleteButtonRect();
if(deleteRect.contains(evt.getX(), evt.getY()) &&
evt.getID() == MouseEvent.MOUSE_CLICKED)
{
clearTextField(this);
}
}
/**
* Implements parent paintSafely method and enables antialiasing.
* @param g the <tt>Graphics</tt> object that notified us
*/
@Override
protected void paintSafely(Graphics g)
{
customPaintBackground(g);
super.paintSafely(g);
}
/**
* Paints the background of the associated component.
* @param g the <tt>Graphics</tt> object used for painting
*/
@Override
protected void customPaintBackground(Graphics g)
{
Graphics2D g2 = (Graphics2D) g.create();
try
{
AntialiasingManager.activateAntialiasing(g2);
super.customPaintBackground(g2);
}
finally
{
g2.dispose();
}
}
}
}