/* * 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 kss = new ArrayList(); 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 kss = new ArrayList(); 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 TextFieldUI to clear */ public void clearTextField(SIPCommTextFieldUI ui) { List kss = new ArrayList(); 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 CallField. * * @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 SIPCommTextFieldUI. */ 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 Graphics 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 Graphics 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(); } } } }