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.kernel.modules.pattern; 22 23 import java.awt.BorderLayout; 24 import java.awt.GridBagConstraints; 25 import java.awt.GridBagLayout; 26 import java.awt.GridLayout; 27 import java.awt.Insets; 28 import java.awt.event.ActionEvent; 29 import java.awt.event.ActionListener; 30 import java.awt.event.KeyAdapter; 31 import java.awt.event.KeyEvent; 32 import java.awt.event.MouseAdapter; 33 import java.awt.event.MouseEvent; 34 import java.util.ArrayList; 35 import java.util.Collections; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Map.Entry; 39 40 import javax.swing.BorderFactory; 41 import javax.swing.JButton; 42 import javax.swing.JComboBox; 43 import javax.swing.JPanel; 44 import javax.swing.JScrollPane; 45 import javax.swing.JTable; 46 import javax.swing.JTextArea; 47 import javax.swing.JTextField; 48 import javax.swing.SwingUtilities; 49 import javax.swing.table.DefaultTableModel; 50 51 import net.sourceforge.atunes.gui.images.Images; 52 import net.sourceforge.atunes.gui.views.controls.AbstractCustomDialog; 53 import net.sourceforge.atunes.model.IControlsBuilder; 54 import net.sourceforge.atunes.model.IFrame; 55 import net.sourceforge.atunes.model.IStateRepository; 56 import net.sourceforge.atunes.utils.I18nUtils; 57 import net.sourceforge.atunes.utils.StringUtils; 58 59 /** 60 * This class represents a dialog used to enter a pattern It contains a preview 61 * table to see in real time how pattern will be applied 62 * 63 * @author fleax 64 */ 65 public final class PatternInputDialog extends AbstractCustomDialog { 66 67 private final class OkActionListener implements ActionListener { 68 private final boolean massiveRecognition; 69 OkActionListener(final boolean massiveRecognition)70 private OkActionListener(final boolean massiveRecognition) { 71 this.massiveRecognition = massiveRecognition; 72 } 73 74 @Override actionPerformed(final ActionEvent e)75 public void actionPerformed(final ActionEvent e) { 76 PatternInputDialog.this.result = (String) PatternInputDialog.this.patternComboBox 77 .getSelectedItem(); 78 79 if (PatternInputDialog.this.result != null 80 && !PatternInputDialog.this.result.trim().equals("")) { 81 // Upper case all patterns found in result 82 for (AbstractPattern pattern : PatternInputDialog.this.patterns 83 .getPatternsList()) { 84 PatternInputDialog.this.result = PatternInputDialog.this.result 85 .replace(pattern.getPattern().toLowerCase(), 86 pattern.getPattern()); 87 } 88 89 // If pattern was not already used add to list of previously 90 // used patterns 91 List<String> previousPatterns = null; 92 if (this.massiveRecognition) { 93 previousPatterns = PatternInputDialog.this.stateRepository 94 .getMassiveRecognitionPatterns(); 95 } else { 96 previousPatterns = PatternInputDialog.this.stateRepository 97 .getRecognitionPatterns(); 98 } 99 100 // Create previous list if necessary 101 if (previousPatterns == null) { 102 previousPatterns = new ArrayList<String>(); 103 if (this.massiveRecognition) { 104 PatternInputDialog.this.stateRepository 105 .setMassiveRecognitionPatterns(previousPatterns); 106 } else { 107 PatternInputDialog.this.stateRepository 108 .setRecognitionPatterns(previousPatterns); 109 } 110 } 111 112 // Test 113 if (!previousPatterns.contains(PatternInputDialog.this.result)) { 114 previousPatterns.add(PatternInputDialog.this.result); 115 } 116 } 117 dispose(); 118 } 119 } 120 121 private static final long serialVersionUID = -5789081662254435503L; 122 123 /** The combo box used to enter or select pattern */ 124 private JComboBox patternComboBox; 125 126 /** Table used to show pattern replace preview */ 127 private JTable patternPreviewTable; 128 129 /** Table used to show available patterns */ 130 private JTable availablePatternsTable; 131 132 /** String used to preview pattern entered */ 133 private String previewString = null; 134 135 /** The pattern entered */ 136 private String result = null; 137 138 private static final String[] PREVIEW_COLUMN_NAMES = new String[] { 139 I18nUtils.getString("NAME"), I18nUtils.getString("VALUE") }; 140 141 private IStateRepository stateRepository; 142 143 private final boolean massiveRecognition; 144 145 private Patterns patterns; 146 147 private PatternMatcher patternMatcher; 148 149 /** 150 * @param patternMatcher 151 */ setPatternMatcher(final PatternMatcher patternMatcher)152 public void setPatternMatcher(final PatternMatcher patternMatcher) { 153 this.patternMatcher = patternMatcher; 154 } 155 156 /** 157 * @param patterns 158 */ setPatterns(final Patterns patterns)159 public void setPatterns(final Patterns patterns) { 160 this.patterns = patterns; 161 } 162 163 /** 164 * @param stateRepository 165 */ setStateRepository(final IStateRepository stateRepository)166 public void setStateRepository(final IStateRepository stateRepository) { 167 this.stateRepository = stateRepository; 168 } 169 170 /** 171 * Instantiates a new pattern input dialog. 172 * 173 * @param frame 174 * @param massiveRecognition 175 * <code>true</code> if the dialog will be used to enter a 176 * pattern for massive recognition or <code>false</code> for 177 * non-massive recognition (single file level) 178 * @param controlsBuilder 179 */ PatternInputDialog(final IFrame frame, final boolean massiveRecognition, final IControlsBuilder controlsBuilder)180 public PatternInputDialog(final IFrame frame, 181 final boolean massiveRecognition, 182 final IControlsBuilder controlsBuilder) { 183 super(frame, 550, 350, controlsBuilder); 184 this.massiveRecognition = massiveRecognition; 185 } 186 187 @Override initialize()188 public void initialize() { 189 setResizable(false); 190 setIconImage(Images.getImage(Images.APP_LOGO_16).getImage()); 191 setTitle(I18nUtils.getString("PATTERN_INPUT")); 192 193 // Label with instructions 194 JTextArea textArea = getControlsBuilder().createTextArea(); 195 textArea.setText(I18nUtils.getString("PATTERN_INPUT_INSTRUCTIONS")); 196 textArea.setBorder(BorderFactory.createEmptyBorder()); 197 textArea.setWrapStyleWord(true); 198 textArea.setEditable(false); 199 textArea.setLineWrap(true); 200 textArea.setOpaque(false); 201 202 // Combo box used to enter pattern 203 List<String> previousPatterns = null; 204 if (this.massiveRecognition) { 205 previousPatterns = this.stateRepository 206 .getMassiveRecognitionPatterns(); 207 } else { 208 previousPatterns = this.stateRepository.getRecognitionPatterns(); 209 } 210 // Sort list 211 if (previousPatterns != null) { 212 Collections.sort(previousPatterns); 213 } 214 this.patternComboBox = new JComboBox( 215 previousPatterns != null ? previousPatterns 216 .toArray(new String[previousPatterns.size()]) 217 : new String[0]); 218 this.patternComboBox.setEditable(true); 219 220 JPanel patternPreviewPanel = new JPanel(new BorderLayout()); 221 this.patternPreviewTable = getLookAndFeel().getTable(); 222 JScrollPane patternPreviewTableScrollPane = getControlsBuilder() 223 .createScrollPane(this.patternPreviewTable); 224 patternPreviewPanel.add(patternPreviewTableScrollPane, 225 BorderLayout.CENTER); 226 patternPreviewPanel.setBorder(BorderFactory.createTitledBorder( 227 BorderFactory.createEmptyBorder(), 228 I18nUtils.getString("PREVIEW"))); 229 230 JPanel availablePatternsPanel = new JPanel(new BorderLayout()); 231 this.availablePatternsTable = getLookAndFeel().getTable(); 232 this.availablePatternsTable.addMouseListener(new MouseAdapter() { 233 @Override 234 public void mouseClicked(final MouseEvent e) { 235 if (e.getClickCount() == 2) { 236 // Get pattern being clicked 237 int row = PatternInputDialog.this.availablePatternsTable 238 .rowAtPoint(e.getPoint()); 239 // Access model to get pattern selected 240 String pattern = ((AvailablePatternsDefaultTableModel) PatternInputDialog.this.availablePatternsTable 241 .getModel()).getPatternAtRow(row); 242 // Add pattern to current one 243 String newPattern = StringUtils.getString( 244 PatternInputDialog.this.patternComboBox.getEditor() 245 .getItem(), pattern); 246 PatternInputDialog.this.patternComboBox.getEditor() 247 .setItem(newPattern); 248 PatternInputDialog.this.patternComboBox 249 .setSelectedItem(newPattern); 250 // Update pattern preview 251 previewPattern(PatternInputDialog.this.massiveRecognition); 252 } 253 } 254 }); 255 JScrollPane availablePatternsScrollPane = getControlsBuilder() 256 .createScrollPane(this.availablePatternsTable); 257 availablePatternsPanel.add(availablePatternsScrollPane, 258 BorderLayout.CENTER); 259 availablePatternsPanel.setBorder(BorderFactory.createTitledBorder( 260 BorderFactory.createEmptyBorder(), 261 I18nUtils.getString("AVAILABLE_PATTERNS"))); 262 263 JButton okButton = new JButton(I18nUtils.getString("OK")); 264 ActionListener okListener = new OkActionListener( 265 this.massiveRecognition); 266 okButton.addActionListener(okListener); 267 JButton cancelButton = new JButton(I18nUtils.getString("CANCEL")); 268 cancelButton.addActionListener(new ActionListener() { 269 @Override 270 public void actionPerformed(final ActionEvent e) { 271 PatternInputDialog.this.result = null; 272 dispose(); 273 } 274 }); 275 276 this.patternComboBox.addActionListener(new ActionListener() { 277 @Override 278 public void actionPerformed(final ActionEvent e) { 279 previewPattern(PatternInputDialog.this.massiveRecognition); 280 } 281 }); 282 283 this.patternComboBox.getEditor().getEditorComponent() 284 .addKeyListener(new KeyAdapter() { 285 @Override 286 public void keyTyped(final KeyEvent e) { 287 super.keyTyped(e); 288 289 SwingUtilities.invokeLater(new Runnable() { 290 @Override 291 public void run() { 292 previewPattern(PatternInputDialog.this.massiveRecognition); 293 } 294 }); 295 } 296 }); 297 298 GridLayout gl = new GridLayout(1, 2, 30, 0); 299 JPanel auxPanel = new JPanel(gl); 300 auxPanel.add(okButton); 301 auxPanel.add(cancelButton); 302 303 arrangeDialog(textArea, patternPreviewPanel, availablePatternsPanel, 304 okButton, auxPanel); 305 } 306 arrangeDialog(final JTextArea textArea, final JPanel patternPreviewPanel, final JPanel availablePatternsPanel, final JButton okButton, final JPanel auxPanel)307 private void arrangeDialog(final JTextArea textArea, 308 final JPanel patternPreviewPanel, 309 final JPanel availablePatternsPanel, final JButton okButton, 310 final JPanel auxPanel) { 311 JPanel panel = new JPanel(new GridBagLayout()); 312 GridBagConstraints c = new GridBagConstraints(); 313 c.gridx = 0; 314 c.gridy = 0; 315 c.weightx = 1; 316 c.gridwidth = 2; 317 c.fill = GridBagConstraints.HORIZONTAL; 318 c.insets = new Insets(10, 10, 10, 10); 319 panel.add(textArea, c); 320 c.gridy = 1; 321 c.insets = new Insets(5, 30, 5, 30); 322 panel.add(this.patternComboBox, c); 323 c.gridx = 0; 324 c.gridy = 2; 325 c.weightx = 0.7; 326 c.weighty = 1; 327 c.gridwidth = 1; 328 c.fill = GridBagConstraints.BOTH; 329 c.insets = new Insets(5, 5, 5, 5); 330 panel.add(patternPreviewPanel, c); 331 c.gridx = 1; 332 c.weightx = 0.3; 333 panel.add(availablePatternsPanel, c); 334 c.gridx = 0; 335 c.gridy = 3; 336 c.gridwidth = 2; 337 c.weighty = 0; 338 c.fill = GridBagConstraints.NONE; 339 c.anchor = GridBagConstraints.CENTER; 340 c.insets = new Insets(10, 10, 10, 10); 341 panel.add(auxPanel, c); 342 add(panel); 343 getRootPane().setDefaultButton(okButton); 344 } 345 346 /** 347 * Updated preview 348 * 349 * @param massiveRecognition 350 */ previewPattern(final boolean massiveRecognition)351 void previewPattern(final boolean massiveRecognition) { 352 Map<String, String> matches = this.patternMatcher.getPatternMatches( 353 ((JTextField) this.patternComboBox.getEditor() 354 .getEditorComponent()).getText(), this.previewString, 355 massiveRecognition); 356 357 String[][] data = new String[matches.size()][2]; 358 int i = 0; 359 for (Entry<String, String> entry : matches.entrySet()) { 360 data[i][0] = I18nUtils.getString(entry.getKey()); 361 data[i][1] = entry.getValue(); 362 i++; 363 } 364 365 ((DefaultTableModel) this.patternPreviewTable.getModel()) 366 .setDataVector(data, PREVIEW_COLUMN_NAMES); 367 } 368 369 /** 370 * Gets the result. 371 * 372 * @return the result 373 */ getResult()374 public String getResult() { 375 return this.result; 376 } 377 378 /** 379 * Show this dialog 380 * 381 * @param availablePatterns 382 * @param previewString 383 */ show(final List<AbstractPattern> availablePatterns, final String previewString)384 public void show(final List<AbstractPattern> availablePatterns, 385 final String previewString) { 386 this.previewString = previewString; 387 this.patternComboBox.setSelectedIndex(-1); 388 389 String[][] patternsMatrix = new String[availablePatterns.size()][2]; 390 int i = 0; 391 for (AbstractPattern p : availablePatterns) { 392 patternsMatrix[i][0] = p.getPattern(); 393 patternsMatrix[i][1] = p.getDescription(); 394 i++; 395 } 396 // Disable autoresize, as we will control it 397 this.patternPreviewTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 398 this.patternPreviewTable 399 .setColumnModel(new PatternPreviewDefaultTableColumnModel()); 400 DefaultTableModel patternPreviewTableModel = new PatternPreviewDefaultTableModel( 401 new String[0][2], PREVIEW_COLUMN_NAMES); 402 this.patternPreviewTable.setModel(patternPreviewTableModel); 403 404 DefaultTableModel availablePatternsTableModel = new AvailablePatternsDefaultTableModel( 405 patternsMatrix, new String[] { I18nUtils.getString("PATTERN"), 406 I18nUtils.getString("DESCRIPTION") }); 407 this.availablePatternsTable.setModel(availablePatternsTableModel); 408 setVisible(true); 409 this.patternComboBox.requestFocus(); 410 } 411 412 } 413