1 /* 2 * aTunes 3 * Copyright (C) Alex Aranda, Sylvain Gaudard and contributors 4 * 5 * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors 6 * 7 * http://www.atunes.org 8 * http://sourceforge.net/projects/atunes 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 package net.sourceforge.atunes.gui.views.controls; 22 23 import java.awt.Component; 24 import java.awt.ComponentOrientation; 25 import java.awt.Container; 26 import java.awt.Dialog.ModalityType; 27 import java.awt.HeadlessException; 28 import java.awt.event.InputEvent; 29 import java.awt.event.KeyEvent; 30 import java.io.File; 31 32 import javax.swing.BorderFactory; 33 import javax.swing.JDialog; 34 import javax.swing.JFileChooser; 35 import javax.swing.JList; 36 import javax.swing.JScrollPane; 37 import javax.swing.JSplitPane; 38 import javax.swing.JTable; 39 import javax.swing.JTextArea; 40 import javax.swing.JTextField; 41 import javax.swing.JTextPane; 42 import javax.swing.JTree; 43 import javax.swing.KeyStroke; 44 import javax.swing.SwingConstants; 45 import javax.swing.text.DefaultEditorKit; 46 import javax.swing.text.JTextComponent; 47 import javax.swing.text.StyleConstants; 48 import javax.swing.tree.TreeCellRenderer; 49 50 import net.sourceforge.atunes.model.IBeanFactory; 51 import net.sourceforge.atunes.model.IButtonPanel; 52 import net.sourceforge.atunes.model.IColumnModel; 53 import net.sourceforge.atunes.model.IColumnSetPopupMenu; 54 import net.sourceforge.atunes.model.IColumnSetTableModel; 55 import net.sourceforge.atunes.model.IControlsBuilder; 56 import net.sourceforge.atunes.model.IDesktop; 57 import net.sourceforge.atunes.model.ILocaleBean; 58 import net.sourceforge.atunes.model.ILookAndFeelManager; 59 import net.sourceforge.atunes.model.IOSManager; 60 import net.sourceforge.atunes.model.IPopUpButton; 61 import net.sourceforge.atunes.model.IStateCore; 62 import net.sourceforge.atunes.model.ITreeCellRendererCode; 63 import net.sourceforge.atunes.utils.ClipboardFacade; 64 65 /** 66 * Factory to build UI components 67 * 68 * @author alex 69 * 70 */ 71 public class ControlsBuilder implements IControlsBuilder { 72 73 private static final JTextComponent.KeyBinding[] MAC_OS_BINDINGS = { 74 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, 75 InputEvent.CTRL_MASK), 76 DefaultEditorKit.defaultKeyTypedAction), 77 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, 78 InputEvent.CTRL_MASK), 79 DefaultEditorKit.defaultKeyTypedAction), 80 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_X, 81 InputEvent.CTRL_MASK), 82 DefaultEditorKit.defaultKeyTypedAction), 83 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_A, 84 InputEvent.CTRL_MASK), 85 DefaultEditorKit.defaultKeyTypedAction), 86 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke( 87 KeyEvent.VK_LEFT, InputEvent.CTRL_MASK), 88 DefaultEditorKit.defaultKeyTypedAction), 89 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke( 90 KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK), 91 DefaultEditorKit.defaultKeyTypedAction), 92 93 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_C, 94 InputEvent.META_MASK), DefaultEditorKit.copyAction), 95 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_V, 96 InputEvent.META_MASK), DefaultEditorKit.pasteAction), 97 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_X, 98 InputEvent.META_MASK), DefaultEditorKit.cutAction), 99 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_A, 100 InputEvent.META_MASK), DefaultEditorKit.selectAllAction), 101 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke( 102 KeyEvent.VK_LEFT, InputEvent.META_MASK), 103 DefaultEditorKit.beginLineAction), 104 new JTextComponent.KeyBinding(KeyStroke.getKeyStroke( 105 KeyEvent.VK_RIGHT, InputEvent.META_MASK), 106 DefaultEditorKit.endLineAction) }; 107 108 private IOSManager osManager; 109 110 private ILookAndFeelManager lookAndFeelManager; 111 112 private ClipboardFacade clipboard; 113 114 private IBeanFactory beanFactory; 115 116 /** The component orientation. */ 117 private ComponentOrientation componentOrientation; 118 119 private IDesktop desktop; 120 121 /** 122 * @param desktop 123 */ setDesktop(final IDesktop desktop)124 public void setDesktop(final IDesktop desktop) { 125 this.desktop = desktop; 126 } 127 128 /** 129 * @param beanFactory 130 */ setBeanFactory(final IBeanFactory beanFactory)131 public void setBeanFactory(final IBeanFactory beanFactory) { 132 this.beanFactory = beanFactory; 133 } 134 135 /** 136 * @param clipboard 137 */ setClipboard(final ClipboardFacade clipboard)138 public void setClipboard(final ClipboardFacade clipboard) { 139 this.clipboard = clipboard; 140 } 141 142 /** 143 * @param lookAndFeelManager 144 */ setLookAndFeelManager( final ILookAndFeelManager lookAndFeelManager)145 public void setLookAndFeelManager( 146 final ILookAndFeelManager lookAndFeelManager) { 147 this.lookAndFeelManager = lookAndFeelManager; 148 } 149 150 /** 151 * @param osManager 152 */ setOsManager(final IOSManager osManager)153 public void setOsManager(final IOSManager osManager) { 154 this.osManager = osManager; 155 } 156 157 @Override createTextArea()158 public JTextArea createTextArea() { 159 JTextArea textArea = new JTextArea(); 160 new EditionPopUpMenu(textArea, this.clipboard, this.osManager); 161 return textArea; 162 } 163 164 @Override createTextField()165 public JTextField createTextField() { 166 JTextField textField = new JTextField(); 167 initializeTextField(textField); 168 new EditionPopUpMenu(textField, this.clipboard, this.osManager); 169 return textField; 170 } 171 172 @Override createTextPane(final Integer alignJustified)173 public JTextPane createTextPane(final Integer alignJustified) { 174 CustomTextPane textPane = new CustomTextPane(alignJustified, this); 175 // Register look and feel change listener 176 this.lookAndFeelManager.addLookAndFeelChangeListener(textPane); 177 new EditionPopUpMenu(textPane, this.clipboard, this.osManager); 178 return textPane; 179 } 180 181 @Override createReadOnlyTextPane(final String text)182 public JTextPane createReadOnlyTextPane(final String text) { 183 JTextPane textPane = createTextPane(null); 184 textPane.setEditable(false); 185 textPane.setBorder(BorderFactory.createEmptyBorder()); 186 textPane.setOpaque(false); 187 textPane.setText(text); 188 return textPane; 189 } 190 191 /** 192 * Sets custom properties to text fields 193 * 194 * @param customTextField 195 */ initializeTextField(final JTextField customTextField)196 private void initializeTextField(final JTextField customTextField) { 197 if (this.osManager.isMacOsX()) { 198 JTextComponent.loadKeymap(customTextField.getKeymap(), 199 MAC_OS_BINDINGS, customTextField.getActions()); 200 } 201 } 202 203 @Override createPlayPauseButton()204 public PlayPauseButton createPlayPauseButton() { 205 return this.beanFactory.getBean(PlayPauseButton.class); 206 } 207 208 @Override createNextButton()209 public NextButton createNextButton() { 210 return this.beanFactory.getBean(NextButton.class); 211 } 212 213 @Override createPreviousButton()214 public PreviousButton createPreviousButton() { 215 return this.beanFactory.getBean(PreviousButton.class); 216 } 217 218 @Override createStopButton()219 public StopButton createStopButton() { 220 return this.beanFactory.getBean(StopButton.class); 221 } 222 223 @Override applyComponentOrientation(final Container... containers)224 public void applyComponentOrientation(final Container... containers) { 225 if (this.componentOrientation == null) { 226 setComponentOrientation(); 227 } 228 for (Container container : containers) { 229 container.applyComponentOrientation(this.componentOrientation); 230 } 231 } 232 233 @Override getComponentOrientation()234 public ComponentOrientation getComponentOrientation() { 235 if (this.componentOrientation == null) { 236 setComponentOrientation(); 237 } 238 return this.componentOrientation; 239 } 240 241 /** 242 * Returns the component orientation as a SwingConstant. 243 * 244 * @param locale 245 * @return The component orientation as a SwingConstant 246 */ 247 @Override getComponentOrientationAsSwingConstant()248 public int getComponentOrientationAsSwingConstant() { 249 if (this.componentOrientation == null) { 250 setComponentOrientation(); 251 } 252 return this.componentOrientation.isLeftToRight() ? SwingConstants.LEFT 253 : SwingConstants.RIGHT; 254 } 255 256 /** 257 * Returns the component orientation as a text style constant. 258 * 259 * @return The component orientation as a SwingConstant 260 */ 261 @Override getComponentOrientationAsTextStyleConstant()262 public int getComponentOrientationAsTextStyleConstant() { 263 if (this.componentOrientation == null) { 264 setComponentOrientation(); 265 } 266 return this.componentOrientation.isLeftToRight() ? StyleConstants.ALIGN_LEFT 267 : StyleConstants.ALIGN_RIGHT; 268 } 269 270 /** 271 * Sets the component orientation. 272 * 273 * @param locale 274 */ setComponentOrientation()275 private void setComponentOrientation() { 276 this.componentOrientation = ComponentOrientation.LEFT_TO_RIGHT; 277 ILocaleBean locale = this.beanFactory.getBean(IStateCore.class) 278 .getLocale(); 279 if (locale != null) { 280 if ("ug".equalsIgnoreCase(locale.getLocale().getLanguage())) { 281 this.componentOrientation = ComponentOrientation.RIGHT_TO_LEFT; 282 } else { 283 this.componentOrientation = ComponentOrientation 284 .getOrientation(locale.getLocale()); 285 } 286 } 287 } 288 289 @Override createPopUpButton(final int menuPosition)290 public IPopUpButton createPopUpButton(final int menuPosition) { 291 return new PopUpButton(menuPosition, this.lookAndFeelManager, this); 292 } 293 294 @Override createSplitPane(final int type)295 public JSplitPane createSplitPane(final int type) { 296 return new CustomSplitPane(type, this, this.lookAndFeelManager); 297 } 298 299 @Override getSplitPaneDividerSize()300 public int getSplitPaneDividerSize() { 301 return new CustomSplitPane(JSplitPane.HORIZONTAL_SPLIT, this, 302 this.lookAndFeelManager).getDividerSize(); 303 } 304 305 @Override createColumnSetPopupMenu(final JTable table, final IColumnModel columnModel, final IColumnSetTableModel tableModel)306 public IColumnSetPopupMenu createColumnSetPopupMenu(final JTable table, 307 final IColumnModel columnModel, 308 final IColumnSetTableModel tableModel) { 309 ColumnSetPopupMenu popup = this.beanFactory 310 .getBean(ColumnSetPopupMenu.class); 311 popup.bindTo(table, columnModel, tableModel); 312 return popup; 313 } 314 315 @Override createButtonPanel()316 public IButtonPanel createButtonPanel() { 317 ToggleButtonFlowPanel panel = this.beanFactory 318 .getBean(ToggleButtonFlowPanel.class); 319 this.lookAndFeelManager.addLookAndFeelChangeListener(panel); 320 return panel; 321 } 322 323 @Override getFileChooser()324 public JFileChooser getFileChooser() { 325 return new CustomFileChooser(); 326 } 327 328 @Override getFileChooser(final String path, final String name)329 public JFileChooser getFileChooser(final String path, final String name) { 330 return new CustomFileChooser(path, name); 331 } 332 333 @SuppressWarnings("rawtypes") 334 @Override createScrollPane(final Component component)335 public JScrollPane createScrollPane(final Component component) { 336 if (component instanceof JTable) { 337 return this.lookAndFeelManager.getCurrentLookAndFeel() 338 .getTableScrollPane((JTable) component); 339 } else if (component instanceof JTree) { 340 return this.lookAndFeelManager.getCurrentLookAndFeel() 341 .getTreeScrollPane((JTree) component); 342 } else if (component instanceof JList) { 343 return this.lookAndFeelManager.getCurrentLookAndFeel() 344 .getListScrollPane((JList) component); 345 } else { 346 return this.lookAndFeelManager.getCurrentLookAndFeel() 347 .getScrollPane(component); 348 } 349 } 350 351 @Override getUrlLabel(final String text, final String url)352 public UrlLabel getUrlLabel(final String text, final String url) { 353 return new UrlLabel(this.desktop, text, url); 354 } 355 356 @Override getUrlLabel()357 public UrlLabel getUrlLabel() { 358 return new UrlLabel(this.desktop); 359 } 360 361 @Override getTreeCellRenderer( final ITreeCellRendererCode<?, ?> code)362 public TreeCellRenderer getTreeCellRenderer( 363 final ITreeCellRendererCode<?, ?> code) { 364 return this.lookAndFeelManager.getCurrentLookAndFeel() 365 .getTreeCellRenderer(code); 366 } 367 368 @Override createTable()369 public JTable createTable() { 370 JTable table = new JTable(); 371 this.lookAndFeelManager.getCurrentLookAndFeel().decorateTable(table); 372 return table; 373 } 374 375 private static class CustomFileChooser extends JFileChooser { 376 /** 377 * 378 */ 379 private static final long serialVersionUID = -5589049318786579475L; 380 381 /** 382 * @param path 383 * @param name 384 */ CustomFileChooser(final String path, final String name)385 public CustomFileChooser(final String path, final String name) { 386 super(path); 387 if (name != null) { 388 setSelectedFile(new File(name)); 389 } 390 } 391 392 /** 393 * Default constructor 394 */ CustomFileChooser()395 public CustomFileChooser() { 396 super(); 397 } 398 399 @Override createDialog(final Component parent)400 protected JDialog createDialog(final Component parent) 401 throws HeadlessException { 402 JDialog dialog = super.createDialog(parent); 403 // Use DOCUMENT_MODAL to avoid problems with Linux platforms: 404 // ERROR: Trying to unblock window blocked by another dialog 405 dialog.setModalityType(ModalityType.DOCUMENT_MODAL); 406 return dialog; 407 } 408 }; 409 } 410