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.ThriftActions;
import org.openslx.dozmod.thrift.ThriftActions.DeleteCallback;
import org.openslx.dozmod.thrift.ThriftActions.DownloadCallback;
/**
* 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 = imageListViewer.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) {
imageListViewer.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());
}
}
// TODO This doesn't work, make deselection possible by clicking on empty table space
else if (SwingUtilities.isLeftMouseButton(e)
&& (mouseRowIndex < 0 || mouseRowIndex > imageTable.getRowCount())) {
imageTable.clearSelection();
}
}
});
/**
* Bottom button panel listeners
*/
newButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new ImageCreationWizard(SwingUtilities.getWindowAncestor(me)).setVisible(true);
imageListViewer.refreshList(true, 100);
}
});
newLectureButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startLectureWizard(imageTable.getSelectedItem());
}
});
editButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
openImageDetails(imageTable.getSelectedItem());
}
});
downloadButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performImageDownload(imageTable.getSelectedItem());
}
});
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
deleteImages(imageTable.getSelectedItems());
}
});
switchViewButton.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) {
editButton.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) {
deleteButton.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, "Das gewählte Image 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
*
* @param item the image to check the user's permissions for
*/
private void updateAvailableOptions(ImageSummaryRead item) {
boolean isValid = item != null && item.getLatestVersionId() != null;
boolean singleSelection = !(imageTable.getSelectedRows().length > 1);
boolean download = isValid && ImagePerms.canDownload(item);
boolean link = isValid && ImagePerms.canLink(item);
boolean admin = ImagePerms.canAdmin(item);
downloadButton.setEnabled(download && singleSelection);
newLectureButton.setEnabled(link && singleSelection);
deleteButton.setEnabled(admin || !singleSelection);
popupItemDownload.setEnabled(download && singleSelection);
popupItemNewLecture.setEnabled(link && singleSelection);
popupItemDelete.setEnabled(admin || !singleSelection);
editButton.setEnabled(singleSelection);
}
/********************************************************************************
*
* 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() {
imageListViewer.refreshList(true, 100);
}
});
}
/**
* 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;
downloadButton.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() {
downloadButton.setEnabled(true);
imageListViewer.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(), this);
}
/**
* 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<ImageSummaryRead> imageList) {
boolean failedToDeleteAll = false;
StringBuilder builder = new StringBuilder();
for (ImageSummaryRead image : imageList) {
if (ImagePerms.canAdmin(image)) {
deleteBaseImage(image);
} 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);
}
}
/**
* Callback when download initialised
*
* @param success true if downloading, false otherwise
*/
@Override
public void isDeleted(boolean success) {
imageListViewer.refreshList(success, 1000);
}
/********************************************************************************
*
* CompositePage abstract methods implementation
*
********************************************************************************/
@Override
public boolean requestHide() {
return true;
}
@Override
public void requestShow() {
imageListViewer.refreshList(false, 1);
}
}