package org.openslx.dozmod.gui.window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.List; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.ImageSummaryRead; import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.MainWindow; import org.openslx.dozmod.gui.control.table.ImageTable; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.gui.helper.PopupMenu; import org.openslx.dozmod.gui.window.ImageDetailsWindow.ImageUpdatedCallback; import org.openslx.dozmod.gui.window.layout.ImageListWindowLayout; import org.openslx.dozmod.gui.wizard.ImageCreationWizard; import org.openslx.dozmod.gui.wizard.LectureWizard; import org.openslx.dozmod.permissions.ImagePerms; import org.openslx.dozmod.thrift.ImageLocalDetailsActions; import org.openslx.dozmod.thrift.Session; import org.openslx.dozmod.thrift.ThriftActions; import org.openslx.dozmod.thrift.ThriftActions.DeleteCallback; import org.openslx.dozmod.thrift.ThriftActions.DownloadCallback; import org.openslx.dozmod.thrift.cache.LectureCache; import org.openslx.util.QuickTimer; import org.openslx.util.QuickTimer.Task; /** * Window with the list of available images. * Has filters for the images and buttons to create, edit and delete buttons. */ @SuppressWarnings("serial") public class ImageListWindow extends ImageListWindowLayout implements DownloadCallback, DeleteCallback { private final static Logger LOGGER = Logger.getLogger(ImageListWindow.class); /** * Self-reference */ public final ImageListWindow me = this; /** * The image table held by the ImageListViewer */ public final ImageTable imageTable = ctlImageListViewer.getImageTable(); /** * Popup menu items */ private final JMenuItem popupItemNewLecture = new JMenuItem("Neue Veranstaltung"); private final JMenuItem popupItemEdit = new JMenuItem("Detailansicht"); private final JMenuItem popupItemDelete = new JMenuItem("Löschen"); private final JMenuItem popupItemDownload = new JMenuItem("Download"); /** * Constructor */ public ImageListWindow() { super(); /** * Popup menu for the version table on the right side */ final PopupMenu pop = new PopupMenu(new ActionListener() { public void actionPerformed(ActionEvent e) { if (e.getSource().equals(popupItemNewLecture)) { startLectureWizard(imageTable.getSelectedItem()); } if (e.getSource().equals(popupItemEdit)) { openImageDetails(imageTable.getSelectedItem()); } if (e.getSource().equals(popupItemDownload)) { performImageDownload(imageTable.getSelectedItem()); } if (e.getSource().equals(popupItemDelete)) { deleteImages(imageTable.getSelectedItems()); } } }); imageTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); // add them to the popup menu pop.addMenuItem(popupItemNewLecture); pop.addMenuItem(popupItemEdit); pop.addMenuItem(popupItemDownload); pop.addSeparator(); pop.addMenuItem(popupItemDelete); /** * Table listeners */ imageTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { ImageSummaryRead item = imageTable.getSelectedItem(); updateAvailableOptions(item); } }); imageTable.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_F5) { ctlImageListViewer.refreshList(true, 1); } } }); imageTable.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) { openImageDetails(imageTable.getSelectedItem()); } processClick(e); } @Override public void mousePressed(MouseEvent e) { processClick(e); } @Override public void mouseReleased(MouseEvent e) { processClick(e); } private void processClick(MouseEvent e) { // rowIndex at mouse cursor int mouseRowIndex = imageTable.rowAtPoint(e.getPoint()); // is the click event on an already selected row? boolean alreadySelectedRow = false; for (int i : imageTable.getSelectedRows()) { if (i == mouseRowIndex) { alreadySelectedRow = true; break; } } if (mouseRowIndex >= 0 && mouseRowIndex < imageTable.getRowCount() && SwingUtilities.isRightMouseButton(e)) { // select row if it wasn't in selection before if (!alreadySelectedRow) { imageTable.setRowSelectionInterval(mouseRowIndex, mouseRowIndex); } if (e.isPopupTrigger()) { pop.show(e.getComponent(), e.getX(), e.getY()); } } } }); /** * Bottom button panel listeners */ btnNewVm.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new ImageCreationWizard(SwingUtilities.getWindowAncestor(me)).setVisible(true); ctlImageListViewer.refreshList(true, 100); } }); btnNewLecture.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { startLectureWizard(imageTable.getSelectedItem()); } }); btnEditDetails.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { openImageDetails(imageTable.getSelectedItem()); } }); btnDownload.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { performImageDownload(imageTable.getSelectedItem()); } }); btnDelete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { deleteImages(imageTable.getSelectedItems()); } }); btnShowPublishedImages.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ImagePublishedWindow.open(JOptionPane.getFrameForComponent(me)); } }); btnSwitchView.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MainWindow.showPage(LectureListWindow.class); } }); // Some keyboard shortcuts imageTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "details"); imageTable.getActionMap().put("details", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { btnEditDetails.doClick(); } }); imageTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put( KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete"); imageTable.getActionMap().put("delete", new AbstractAction() { @Override public void actionPerformed(ActionEvent ae) { btnDelete.doClick(); } }); updateAvailableOptions(null); } /******************************************************************************** * * General GUI and table helpers * ********************************************************************************/ /** * Helper to check if the given image has a latest version * * @param image the image to check for a latest version * @return true if the image has a latest version, false otherwise */ private boolean hasLatestVersion(ImageSummaryRead image) { if (image == null) return false; if (image.getLatestVersionId() == null) { Gui.showMessageBox(me, "Die gewählte VM besitzt keine gültige Image-Version", MessageType.ERROR, null, null); return false; } return true; } /** * Updates the buttons/popup menu items according to the user's permissions * and the selection in the table * * @param item the image to check the user's permissions for */ private void updateAvailableOptions(ImageSummaryRead item) { boolean isValid = item != null && item.getLatestVersionId() != null; int selCount = imageTable.getSelectedRows().length; boolean download = isValid && selCount == 1 && ImagePerms.canDownload(item); boolean link = isValid && selCount == 1 && ImagePerms.canLink(item); boolean delete = ImagePerms.canAdmin(item) || selCount > 1; btnDownload.setEnabled(download); btnNewLecture.setEnabled(link); btnDelete.setEnabled(delete); popupItemDownload.setEnabled(download); popupItemNewLecture.setEnabled(link); popupItemDelete.setEnabled(delete); btnEditDetails.setEnabled(selCount == 1); btnShowPublishedImages.setEnabled(true); } public void refresh(boolean force) { ctlImageListViewer.refreshList(force, 1); } /******************************************************************************** * * Helpers triggering the actual actions * ********************************************************************************/ /** * Starts a lecture wizard for the given image if it has a valid version * * @param image image to link the new lecture to */ private void startLectureWizard(ImageSummaryRead image) { if (!hasLatestVersion(image)) return; new LectureWizard(SwingUtilities.getWindowAncestor(this), image, image.getLatestVersionId()).setVisible(true); } /** * Opens the given image details as a popup window * * @param image the image to show the details of */ private void openImageDetails(ImageSummaryRead image) { if (image == null) return; ImageDetailsWindow.open((JFrame) SwingUtilities.getWindowAncestor(me), image.getImageBaseId(), new ImageUpdatedCallback() { public void updated() { ctlImageListViewer.refreshList(true, 100); } }, new ImageLocalDetailsActions(JOptionPane.getFrameForComponent(me))); } /** * Triggers a download of the given image's latest version * * @param image the image to download */ private void performImageDownload(ImageSummaryRead image) { if (!hasLatestVersion(image)) return; btnDownload.setEnabled(false); ThriftActions.initDownload(JOptionPane.getFrameForComponent(this), image.latestVersionId, image.imageName, image.virtId, image.osId, image.fileSize, this); } /** * Callback when download initialized * * @param success true if downloading, false otherwise */ @Override public void downloadInitialized(boolean success) { if (!success) { Gui.asyncExec(new Runnable() { @Override public void run() { btnDownload.setEnabled(true); ctlImageListViewer.refreshList(true, 1000); } }); } } /** * Deletes the latest version of the given image if it has one * * @param image image to delete */ //TODO seems like it's no longer needed. private void deleteBaseImage(final ImageSummaryRead image) { ThriftActions.deleteImageBase(JOptionPane.getFrameForComponent(this), image.getImageBaseId()); } /** * Delete a list of images and display the images, which couldn't be * deleted. * * @param imageList the images to be deleted. */ private void deleteImages(List imageList) { boolean failedToDeleteAll = false; boolean deletedAtLeastOne = false; StringBuilder builder = new StringBuilder(); for (ImageSummaryRead image : imageList) { if (ImagePerms.canAdmin(image)) { deleteBaseImage(image); deletedAtLeastOne = true; } else { failedToDeleteAll = true; builder.append('\n'); builder.append(image.imageName); } } if (failedToDeleteAll) { Gui.showMessageBox("Folgende images konnten nicht gelöscht werden: " + builder.toString(), MessageType.INFO, LOGGER, null); } ctlImageListViewer.refreshList(deletedAtLeastOne, 1000); QuickTimer.scheduleOnce(new Task() { @Override public void fire() { LectureCache.get(true); } }); } /** * Callback when download initialised * * @param success true if downloading, false otherwise */ @Override public void isDeleted(boolean success) { ctlImageListViewer.refreshList(success, 1000); } /******************************************************************************** * * CompositePage abstract methods implementation * ********************************************************************************/ @Override public boolean requestHide() { return true; } @Override public void requestShow() { // we need to enable the "Show published images" button here, since we need to check // Session.getSatApiVersion() which is not set when this class is instantiated ctlImageListViewer.refreshList(false, 1); btnShowPublishedImages.setVisible(Session.isImagePublishSupported()); } }