1 package com.melloware.jukes.gui.view.editor;
2
3 import java.awt.Dimension;
4 import java.awt.event.ActionEvent;
5 import java.awt.event.MouseAdapter;
6 import java.awt.event.MouseEvent;
7 import java.awt.event.MouseListener;
8 import java.io.File;
9 import java.io.IOException;
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.Iterator;
13 import java.util.List;
14
15 import javax.swing.DefaultListModel;
16 import javax.swing.JComboBox;
17 import javax.swing.JComponent;
18 import javax.swing.JFileChooser;
19 import javax.swing.JLabel;
20 import javax.swing.JList;
21 import javax.swing.JPopupMenu;
22 import javax.swing.JTextArea;
23 import javax.swing.JTextField;
24 import javax.swing.JToolBar;
25 import javax.swing.ListSelectionModel;
26 import javax.swing.ProgressMonitor;
27 import javax.swing.Timer;
28 import javax.swing.text.JTextComponent;
29
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33
34 import com.jgoodies.binding.list.SelectionInList;
35 import com.jgoodies.binding.value.ValueModel;
36 import com.jgoodies.forms.builder.PanelBuilder;
37 import com.jgoodies.forms.layout.CellConstraints;
38 import com.jgoodies.forms.layout.FormLayout;
39 import com.jgoodies.uif.action.ActionManager;
40 import com.jgoodies.uif.application.Application;
41 import com.jgoodies.uif.builder.ToolBarBuilder;
42 import com.jgoodies.uif.component.ToolBarButton;
43 import com.jgoodies.uif.panel.SimpleInternalFrame;
44 import com.jgoodies.uifextras.util.UIFactory;
45 import com.jgoodies.validation.view.ValidationComponentUtils;
46 import com.melloware.jukes.db.HibernateDao;
47 import com.melloware.jukes.db.HibernateUtil;
48 import com.melloware.jukes.db.orm.Artist;
49 import com.melloware.jukes.db.orm.Disc;
50 import com.melloware.jukes.db.orm.Track;
51 import com.melloware.jukes.exception.InfrastructureException;
52 import com.melloware.jukes.file.filter.FilterFactory;
53 import com.melloware.jukes.file.image.ChooserImagePreview;
54 import com.melloware.jukes.file.image.ImageFactory;
55 import com.melloware.jukes.file.image.ImageFileView;
56 import com.melloware.jukes.file.tag.MusicTag;
57 import com.melloware.jukes.file.tag.TagFactory;
58 import com.melloware.jukes.gui.tool.Actions;
59 import com.melloware.jukes.gui.tool.Resources;
60 import com.melloware.jukes.gui.view.MainMenuBuilder;
61 import com.melloware.jukes.gui.view.component.AlbumImage;
62 import com.melloware.jukes.gui.view.component.ComponentFactory;
63 import com.melloware.jukes.gui.view.component.TrackListCellRenderer;
64 import com.melloware.jukes.gui.view.dialogs.WebSearchDialog;
65 import com.melloware.jukes.gui.view.tasks.TimerListener;
66 import com.melloware.jukes.gui.view.tasks.UpdateTagsTask;
67 import com.melloware.jukes.gui.view.validation.DiscValidationModel;
68 import com.melloware.jukes.gui.view.validation.IconFeedbackPanel;
69 import com.melloware.jukes.util.JukesValidationMessage;
70 import com.melloware.jukes.util.MessageUtil;
71
72
73
74
75
76
77
78
79
80
81
82
83 @SuppressWarnings("unchecked")
84 public final class DiscEditor
85 extends AbstractEditor {
86
87 private static final Log LOG = LogFactory.getLog(DiscEditor.class);
88 private static final List GENRE_LIST = MusicTag.getGenreTypes();
89 private AlbumImage albumImage;
90 private DefaultListModel listModel;
91 private JComboBox genre;
92 private JComponent discPanel;
93 private JLabel genreLabel;
94 private JLabel location;
95 private JList trackList;
96 private JTextArea notesField;
97 private JTextComponent nameField;
98 private JTextComponent year;
99 private JToolBar headerToolbar;
100 private List tracks;
101 private SimpleInternalFrame listScrollPane;
102
103
104
105
106 public DiscEditor() {
107 super(Resources.DISC_TREE_ICON);
108 }
109
110
111
112
113 public Class getDomainClass() {
114 return Disc.class;
115 }
116
117
118
119
120 public JToolBar getHeaderToolBar() {
121 return headerToolbar;
122 }
123
124
125
126
127 public void build() {
128 initComponents();
129 initComponentAnnotations();
130 initEventHandling();
131
132 discPanel = buildDiscPanel();
133
134 FormLayout layout = new FormLayout("fill:pref:grow", "p, 12px, p, p, 12px, p, 12px, p, 12px, p");
135
136 setLayout(layout);
137 PanelBuilder builder = new PanelBuilder(layout, this);
138 builder.setDefaultDialogBorder();
139 CellConstraints cc = new CellConstraints();
140
141 builder.add(buildMusicPanel(), cc.xy(1, 1));
142 builder.add(buildHintAreaPane(), cc.xy(1, 3));
143 builder.addSeparator(Resources.getString("label.disc"), cc.xy(1, 4));
144 builder.add(discPanel, cc.xy(1, 6));
145 JComponent audit = buildAuditInfoPanel();
146 if (this.getSettings().isAuditInfo()) {
147 builder.addSeparator(Resources.getString("label.auditinfo"), cc.xy(1, 8));
148 builder.add(audit, cc.xy(1, 10));
149 }
150 }
151
152
153
154
155
156 public void commit() {
157 commit(true);
158 }
159
160
161
162
163 public void delete() {
164 super.delete();
165 try {
166 if (!MessageUtil.confirmDelete(this)) {
167 return;
168 }
169
170 setBusyCursor(true);
171 HibernateUtil.beginTransaction();
172 Disc disc = getDisc();
173 final Artist artist = disc.getArtist();
174 HibernateDao.refresh(artist);
175 artist.getDiscs().remove(disc);
176 HibernateDao.refresh(disc);
177 HibernateDao.delete(disc);
178 HibernateUtil.commitTransaction();
179
180
181 getValidationModel().setDirty(false);
182
183 if (artist.getDiscs().size() == 0) {
184
185 ActionManager.get(Actions.REFRESH_ID).actionPerformed(null);
186 } else {
187
188 this.getMainModule().refreshSelection(disc, Resources.NODE_DELETED);
189 }
190 } catch (Exception ex) {
191 LOG.error("Error deleting disc.", ex);
192 HibernateUtil.rollbackTransaction();
193 } finally {
194 setBusyCursor(false);
195 }
196 }
197
198
199
200
201 public void findCover() {
202 Disc disc = getDisc();
203 if (disc.isNotValid()) {
204 LOG.error(Resources.getString("messages.discnotexists"));
205 return;
206 }
207
208 updateModel();
209
210
211 boolean hasErrors = hasErrors();
212 if (hasErrors) {
213 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
214 return;
215 }
216
217 final File currentDir = new File(getDisc().getLocation());
218 JFileChooser chooser = new JFileChooser();
219 chooser.setApproveButtonText("Select");
220 chooser.setDialogTitle("Find Cover Image");
221 chooser.setCurrentDirectory(currentDir);
222 chooser.addChoosableFileFilter(FilterFactory.imageFileFilter());
223 chooser.setAcceptAllFileFilterUsed(false);
224 chooser.setFileView(new ImageFileView());
225 chooser.setAccessory(new ChooserImagePreview(chooser));
226 chooser.setMultiSelectionEnabled(false);
227 int returnVal = chooser.showOpenDialog(Application.getDefaultParentFrame());
228 if (returnVal != JFileChooser.APPROVE_OPTION) {
229 return;
230 }
231
232 File file = chooser.getSelectedFile();
233
234 try {
235 setBusyCursor(true);
236 HibernateUtil.beginTransaction();
237 disc.setCoverUrl(file.getAbsolutePath());
238 HibernateDao.persist(disc);
239 HibernateUtil.commitTransaction();
240
241
242 updateView();
243 } catch (InfrastructureException ex) {
244 HibernateUtil.rollbackTransaction();
245 LOG.error("Disc must be unique within an artist. \n\nMust have different Name than all other discs. ");
246 HibernateDao.refresh(disc);
247 } catch (Exception ex) {
248 HibernateUtil.rollbackTransaction();
249 LOG.error("Error updating cover image.", ex);
250 HibernateDao.refresh(disc);
251 } finally {
252 setBusyCursor(false);
253 }
254 }
255
256
257
258
259 public void renameFiles() {
260 if (getDisc().isNotValid()) {
261 LOG.error(Resources.getString("messages.discnotexists"));
262 return;
263 }
264
265 updateModel();
266
267
268 boolean hasErrors = hasErrors();
269 if (hasErrors) {
270 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
271 return;
272 }
273
274 MusicTag musicTag = null;
275 try {
276 setBusyCursor(true);
277 for (Iterator iter = getDisc().getTracks().iterator(); iter.hasNext();) {
278 Track track = (Track)iter.next();
279 final File file = new File(track.getTrackUrl());
280
281 if (file.exists()) {
282 musicTag = TagFactory.getTag(file);
283 if (musicTag.renameFile(this.getSettings().getFileFormatMusic())) {
284 track.setTrackUrl(musicTag.getAbsolutePath());
285 }
286 }
287 }
288 commit(false);
289 } catch (InfrastructureException ex) {
290 LOG.error(ex.getMessage());
291 } catch (Exception ex) {
292 LOG.error("Error renaming file.", ex);
293 } finally {
294 setBusyCursor(false);
295 }
296 }
297
298
299
300
301 public void rollback() {
302 super.rollback();
303 try {
304 setBusyCursor(true);
305
306 Disc disc = getDisc();
307 HibernateDao.refresh(disc);
308 updateView();
309 super.rollback();
310 } catch (Exception ex) {
311 LOG.error("Error refreshing disc.", ex);
312 } finally {
313 setBusyCursor(false);
314 }
315 }
316
317
318
319
320 public void webSearch() {
321 super.webSearch();
322 final Disc disc = getDisc();
323 if (disc.isNotValid()) {
324 LOG.error(Resources.getString("messages.discnotexists"));
325 return;
326 }
327
328 if (hasErrors()) {
329 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
330 return;
331 }
332
333 final WebSearchDialog dialog = new WebSearchDialog(getMainFrame(), getSettings());
334 dialog.setSelectedArtist(disc.getArtist().getName());
335 dialog.setSelectedDisc(disc.getName());
336 dialog.open();
337
338
339 if (dialog.hasBeenCanceled()) {
340 return;
341 }
342
343
344 boolean modified = false;
345
346
347 final String[] checkList = { "- Disc", "-Disc", "- disc" };
348 if (((StringUtils.isNotBlank(dialog.getSelectedDisc()))
349 && (StringUtils.indexOfAny(nameField.getText(), checkList) <= 0))) {
350 disc.setName(dialog.getSelectedDisc());
351 nameField.setText(dialog.getSelectedDisc());
352 modified = true;
353 }
354 if ((StringUtils.isNotBlank(dialog.getSelectedYear()))
355 && (Integer.valueOf(dialog.getSelectedYear()).intValue() < Integer.valueOf(year.getText()).intValue())) {
356 disc.setYear(dialog.getSelectedYear());
357 year.setText(dialog.getSelectedYear());
358 modified = true;
359 }
360 if (dialog.getSelectedImage() != null) {
361 try {
362 if (StringUtils.isNotBlank(disc.getCoverUrl())) {
363 ImageFactory.saveImage(dialog.getSelectedImage(), disc.getCoverUrl());
364 } else {
365 String filename = ImageFactory.saveImageWithFileFormat(dialog.getSelectedImage(),
366 this.getSettings().getFileFormatImage(),
367 disc.getLocation(),
368 disc.getArtist().getName(), disc.getName());
369 disc.setCoverUrl(filename);
370 }
371 albumImage.setImage(ImageFactory.getDiscImage(disc.getCoverUrl()).getImage());
372 } catch (IOException ex) {
373 LOG.error("Error saving cover image.", ex);
374 }
375 }
376
377
378 commit(modified);
379 }
380
381
382
383
384
385
386 protected String getTitleSuffix() {
387 return getDisc().getDisplayText(getSettings().getDisplayFormatDisc());
388 }
389
390
391
392
393 protected void updateModel() {
394 Disc disc = getDisc();
395
396
397 if (!StringUtils.equals(disc.getName(), nameField.getText())) {
398 disc.setName(nameField.getText());
399 }
400
401 if (!StringUtils.equalsIgnoreCase(disc.getYear(), year.getText())) {
402 disc.setYear(year.getText());
403 }
404
405 if (!StringUtils.equalsIgnoreCase(disc.getGenre(), (String)genre.getSelectedItem())) {
406 disc.setGenre((String)genre.getSelectedItem());
407 }
408
409 if (!StringUtils.equalsIgnoreCase(disc.getNotes(), notesField.getText())) {
410 disc.setNotes(notesField.getText());
411 }
412 }
413
414
415
416
417 protected void updateView() {
418 Disc disc = getDisc();
419
420 genre.setSelectedItem(null);
421
422
423 nameField.setText(disc.getName());
424 year.setText(disc.getYear());
425 genre.setSelectedItem(disc.getGenre());
426 genreLabel.setText(disc.getGenre());
427 location.setText(disc.getLocation());
428 location.setToolTipText(disc.getLocation());
429 notesField.setText(disc.getNotes());
430 createdDateLabel.setText(DATE_FORMAT.format(disc.getCreatedDate()));
431 createdByLabel.setText(disc.getCreatedUser());
432 modifiedDateLabel.setText(DATE_FORMAT.format(disc.getModifiedDate()));
433 modifiedByLabel.setText(disc.getModifiedUser());
434 listModel.removeAllElements();
435 tracks = new ArrayList();
436 for (Iterator iter = disc.getTracks().iterator(); iter.hasNext();) {
437 final Track track = (Track)iter.next();
438 final String name = track.getDisplayText(getSettings().getDisplayFormatTrack());
439 final JukesValidationMessage message = new JukesValidationMessage(name, null, track);
440 tracks.add(message);
441 }
442 Collections.sort(tracks, TrackListCellRenderer.TRACK_COMPARATOR);
443 for (Iterator iter = tracks.iterator(); iter.hasNext();) {
444 JukesValidationMessage message = (JukesValidationMessage)iter.next();
445 listModel.addElement(message);
446 }
447
448
449 int dimension = this.getSettings().getCoverSizeLarge();
450 albumImage.setDisc(disc);
451 albumImage.setImage(ImageFactory.getScaledImage(disc.getCoverUrl(), dimension, dimension).getImage());
452 }
453
454
455
456
457
458
459 private Disc getDisc() {
460 return (Disc)getModel();
461 }
462
463
464
465
466
467
468 private JComponent buildDiscPanel() {
469 FormLayout layout = new FormLayout("right:max(14dlu;pref), 4dlu, left:min(80dlu;pref):grow, pref, 4dlu, pref, 25px",
470 "p, 4px, p, 4px, p, 4px, p, 4px, p, 4px");
471
472 layout.setRowGroups(new int[][] {
473 { 1, 3 }
474 });
475 PanelBuilder builder = new PanelBuilder(layout);
476 CellConstraints cc = new CellConstraints();
477
478 builder.addLabel(Resources.getString("label.name") + ": ", cc.xy(1, 1));
479 builder.add(nameField, cc.xyw(3, 1, 3));
480 builder.add(ComponentFactory.createTitleCaseButton(nameField), cc.xy(6, 1));
481 builder.addLabel(Resources.getString("label.genre") + ": ", cc.xy(1, 3));
482 builder.add(genreLabel, cc.xyw(2, 3, 2));
483 builder.add(genre, cc.xyw(3, 3, 3));
484 builder.addLabel(Resources.getString("label.year") + ": ", cc.xy(1, 5));
485 builder.add(year, cc.xy(3, 5));
486 builder.addLabel(Resources.getString("label.file") + ": ", cc.xy(1, 7));
487 builder.add(location, cc.xyw(3, 7, 5));
488 builder.addLabel(Resources.getString("label.notes") + ": ", cc.xy(1, 9, "left,top"));
489 builder.add(notesField, cc.xyw(3, 9, 3));
490
491 return new IconFeedbackPanel(getValidationModel().getValidationResultModel(), builder.getPanel());
492 }
493
494
495
496
497
498
499 private JComponent buildMusicPanel() {
500 FormLayout layout = new FormLayout("left:pref, 4dlu, right:pref", "p");
501
502 layout.setRowGroups(new int[][] {
503 { 1 }
504 });
505 PanelBuilder builder = new PanelBuilder(layout);
506 CellConstraints cc = new CellConstraints();
507 builder.add(listScrollPane, cc.xy(1, 1, "left,top"));
508 builder.add(albumImage, cc.xy(3, 1, "left,top"));
509 return builder.getPanel();
510 }
511
512 private JToolBar buildToolBar() {
513 final ToolBarBuilder bar = new ToolBarBuilder("Disc Toolbar");
514 ToolBarButton button = null;
515 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.UNLOCK_ID);
516 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
517 bar.add(button);
518 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.COMMIT_ID);
519 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
520 bar.add(button);
521 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.ROLLBACK_ID);
522 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
523 bar.add(button);
524 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DELETE_ID);
525 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
526 bar.add(button);
527 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.FILE_RENAME_ID);
528 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
529 bar.add(button);
530 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DISC_COVER_ID);
531 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
532 bar.add(button);
533 button = (ToolBarButton)ComponentFactory.createToolBarButton(Actions.DISC_WEB_ID);
534 button.putClientProperty(Resources.EDITOR_COMPONENT, this);
535 bar.add(button);
536 return bar.getToolBar();
537 }
538
539
540
541
542
543
544
545 private void commit(boolean aUpdateTags) {
546 super.commit();
547 final Disc disc = getDisc();
548 updateModel();
549
550
551 boolean hasErrors = hasErrors();
552 if (hasErrors) {
553 LOG.error(Resources.MESSAGE_EDITOR_ERRORS);
554 return;
555 }
556
557
558 try {
559 setBusyCursor(true);
560 HibernateUtil.beginTransaction();
561 HibernateDao.saveOrUpdate(disc);
562 HibernateUtil.commitTransaction();
563
564
565 updateView();
566 this.getMainModule().refreshSelection(disc, Resources.NODE_CHANGED);
567 } catch (InfrastructureException ex) {
568 HibernateUtil.rollbackTransaction();
569 LOG.error("Disc must be unique within an artist. \n\nMust have different Name than all other discs. ");
570 HibernateDao.refresh(disc);
571 hasErrors = true;
572 } catch (Exception ex) {
573 HibernateUtil.rollbackTransaction();
574 LOG.error("Error updating disc.", ex);
575 HibernateDao.refresh(disc);
576 hasErrors = true;
577 } finally {
578 setBusyCursor(false);
579 }
580
581 if (!hasErrors) {
582 if (aUpdateTags) {
583
584 task = new UpdateTagsTask(disc);
585 progressMonitor = new ProgressMonitor(getMainFrame(), Resources.getString("messages.updatetracks"), "",
586 0, (int)task.getLengthOfTask());
587 progressMonitor.setProgress(0);
588 progressMonitor.setMillisToDecideToPopup(10);
589 task.go();
590 timer = new Timer(50, null);
591 timer.addActionListener(new TimerListener(progressMonitor, task, timer));
592 timer.start();
593 } else {
594 MessageUtil.showSuccess(this);
595 }
596 super.commit();
597 }
598 }
599
600
601
602
603 private void initComponentAnnotations() {
604 ValidationComponentUtils.setInputHint(nameField, "Name is Mandatory, Length <= 100");
605 ValidationComponentUtils.setMandatory(nameField, true);
606 ValidationComponentUtils.setMessageKey(nameField, "Disc.Name");
607 ValidationComponentUtils.setInputHint(year, "Year is Mandatory, must be exactly 4 digits between 0000-9999");
608 ValidationComponentUtils.setMandatory(year, true);
609 ValidationComponentUtils.setMessageKey(year, "Disc.Year");
610 ValidationComponentUtils.setMessageKey(genre, "Disc.Genre");
611 ValidationComponentUtils.setInputHint(notesField, "Notes Length <= 500");
612 ValidationComponentUtils.setMessageKey(notesField, "Disc.Notes");
613 }
614
615
616
617
618 private void initComponents() {
619 validationModel = new DiscValidationModel(new Disc());
620
621 headerToolbar = buildToolBar();
622 nameField = ComponentFactory.createTextField(validationModel.getModel(Disc.PROPERTYNAME_NAME), false);
623 year = ComponentFactory.createTextField(validationModel.getModel(Disc.PROPERTYNAME_YEAR), false);
624 ((JTextField)year).setColumns(5);
625 final ValueModel genreChoiceModel = validationModel.getModel(Disc.PROPERTYNAME_GENRE);
626 genreLabel = new JLabel();
627 genreLabel.setName("GENRE");
628 genre = ComponentFactory.createComboBox(new SelectionInList(GENRE_LIST, genreChoiceModel));
629 notesField = ComponentFactory.createTextArea(getValidationModel().getModel(Disc.PROPERTYNAME_NOTES), false);
630 notesField.setLineWrap(true);
631 notesField.setWrapStyleWord(true);
632 notesField.setRows(3);
633 location = ComponentFactory.createLabel(getValidationModel().getModel(Disc.PROPERTYNAME_LOCATION));
634 albumImage = new AlbumImage(new Dimension(this.getSettings().getCoverSizeLarge(), this.getSettings().getCoverSizeLarge()));
635 listModel = new DefaultListModel();
636
637 trackList = new JList(listModel);
638 trackList.setFocusable(true);
639 trackList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
640 trackList.setSelectedIndex(0);
641 trackList.setVisibleRowCount(20);
642 trackList.setCellRenderer(new TrackListCellRenderer(this.getSettings()));
643 final JPopupMenu popup = MainMenuBuilder.buildPlayerPopupMenu(trackList);
644 MouseListener popupListener = new ListPopupListener(popup);
645 trackList.addMouseListener(popupListener);
646 trackList.add(popup);
647 listScrollPane = new SimpleInternalFrame(Resources.getString("label.tracks"));
648 listScrollPane.setFrameIcon(Resources.TRACK_TREE_ICON);
649 listScrollPane.setContent(UIFactory.createStrippedScrollPane(trackList));
650 listScrollPane.setSelected(true);
651 }
652
653
654 private static class ListPopupListener
655 extends MouseAdapter {
656
657 final JPopupMenu popup;
658
659 public ListPopupListener(JPopupMenu popup) {
660 this.popup = popup;
661 }
662
663 public void mousePressed(MouseEvent evt) {
664 maybeShowPopup(evt);
665
666
667
668 if ((((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) && (evt.getClickCount() == 2)) ||
669 ((evt.getModifiers() & MouseEvent.BUTTON2_MASK) != 0))
670 {
671 LOG.debug("[List left double clickedor middle clicked].");
672 JComponent source = (JComponent)evt.getSource();
673 final ActionEvent event = new ActionEvent(source, 1, Actions.PLAYER_QUEUE_ID);
674 source.putClientProperty(Resources.EDITOR_COMPONENT, source);
675 ActionManager.get(Actions.PLAYER_QUEUE_ID).actionPerformed(event);
676 }
677 }
678
679 public void mouseReleased(MouseEvent e) {
680 maybeShowPopup(e);
681 }
682
683 private void maybeShowPopup(MouseEvent e) {
684 if (e.isPopupTrigger()) {
685 ActionManager.get(Actions.TRACK_PLAY_IMMEDIATE_ID).setEnabled(true);
686
687
688 popup.show(e.getComponent(), e.getX(), e.getY());
689 }
690 }
691
692 }
693
694 }