package org.openslx.dozmod.gui.window;
import java.awt.Color;
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.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
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.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.ImageDetailsRead;
import org.openslx.bwlp.thrift.iface.ImageVersionDetails;
import org.openslx.bwlp.thrift.iface.LectureSummary;
import org.openslx.bwlp.thrift.iface.UserInfo;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.control.table.ListTable.ListModel;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.PopupMenu;
import org.openslx.dozmod.gui.window.LectureDetailsWindow.LectureUpdatedCallback;
import org.openslx.dozmod.gui.window.layout.LectureListWindowLayout;
import org.openslx.dozmod.gui.wizard.LectureWizard;
import org.openslx.dozmod.permissions.LecturePerms;
import org.openslx.dozmod.thrift.Session;
import org.openslx.dozmod.thrift.ThriftActions;
import org.openslx.dozmod.thrift.ThriftActions.DeleteLectureCallback;
import org.openslx.dozmod.thrift.cache.LectureCache;
import org.openslx.dozmod.thrift.cache.UserCache;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
/**
* Window for displaying a table with the available lectures.
* Lectures can be created and deleted here.
*/
@SuppressWarnings("serial")
public class LectureListWindow extends LectureListWindowLayout {
private final static Logger LOGGER = Logger.getLogger(LectureListWindow.class);
public final LectureListWindow me = this;
// Filter types as an enum
public static enum FilterType {
ALL("Alle anzeigen"),
OWN("Nur eigene/zugewiesene anzeigen"),
ACTIVE("Nur aktive anzeigen"),
EDITABLE("Nur editierbare anzeigen"),
EXPIRING("Bald auslaufende anzeigen");
private final String name;
private FilterType(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
private Pattern searchFieldPattern = null;
private final RowFilter<ListModel<LectureSummary>, Integer> filterSearchTerm = new RowFilter<ListModel<LectureSummary>, Integer>() {
public boolean include(Entry<? extends ListModel<LectureSummary>, ? extends Integer> entry) {
LectureSummary lecture = lectureTable.getModelRow(entry.getIdentifier());
if (searchFieldPattern.matcher(lecture.lectureName).find())
return true;
UserInfo user = UserCache.find(lecture.ownerId);
if (user == null)
return false;
if (searchFieldPattern.matcher(user.firstName).find())
return true;
if (searchFieldPattern.matcher(user.lastName).find())
return true;
if (searchFieldPattern.matcher(user.eMail).find())
return true;
return false;
}
};
// filter for own lectures
private final RowFilter<ListModel<LectureSummary>, Integer> filterOwn = new RowFilter<ListModel<LectureSummary>, Integer>() {
public boolean include(Entry<? extends ListModel<LectureSummary>, ? extends Integer> entry) {
LectureSummary lecture = lectureTable.getModelRow(entry.getIdentifier());
return lecture.userPermissions.admin || lecture.ownerId.equals(Session.getUserId());
}
};
// filter for active lectures
private final RowFilter<ListModel<LectureSummary>, Integer> filterActive = new RowFilter<ListModel<LectureSummary>, Integer>() {
public boolean include(Entry<? extends ListModel<LectureSummary>, ? extends Integer> entry) {
return lectureTable.getModelRow(entry.getIdentifier()).isEnabled;
}
};
// filter for editable lectures
private final RowFilter<ListModel<LectureSummary>, Integer> filterEditable = new RowFilter<ListModel<LectureSummary>, Integer>() {
public boolean include(Entry<? extends ListModel<LectureSummary>, ? extends Integer> entry) {
return LecturePerms.canEdit(lectureTable.getModelRow(entry.getIdentifier()));
}
};
// filter for expiring lectures
private final RowFilter<ListModel<LectureSummary>, Integer> filterExpiring = new RowFilter<ListModel<LectureSummary>, Integer>() {
public boolean include(Entry<? extends ListModel<LectureSummary>, ? extends Integer> entry) {
LectureSummary selLect = lectureTable.getModelRow(entry.getIdentifier());
long end = selLect.getEndTime() * 1000l;
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.DATE, 7);
return cal.getTimeInMillis() > end ? true : false;
}
};
/**
* Popup menu items
*/
private JMenuItem popupItemNew = new JMenuItem("Neu");
private JMenuItem popupItemEdit = new JMenuItem("Detailansicht");
private JMenuItem popupItemLinked = new JMenuItem("Imagedetails anzeigen");
private JMenuItem popupItemDownload = new JMenuItem("Verlinktes Image herunterladen");
private JMenuItem popupItemDelete = new JMenuItem("Löschen");
public LectureListWindow() {
super();
// filter the objects in the table depending on the search field
searchTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
@Override
public void changedUpdate(DocumentEvent e) {
// stuff
String str = searchTextField.getText();
if (str == null || str.isEmpty()) {
searchFieldPattern = null;
} else {
try {
searchFieldPattern = Pattern.compile(str, Pattern.CASE_INSENSITIVE);
searchTextField.setForeground(UIManager.getColor("TextField.foreground"));
} catch (PatternSyntaxException ex) {
searchTextField.setForeground(Color.RED);
}
}
applyFilterOnTable();
}
});
filterCbo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
searchTextField.setEnabled(true);
applyFilterOnTable();
}
});
newButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
new LectureWizard(SwingUtilities.getWindowAncestor(me), null, null).setVisible(true);
}
});
editButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
openLectureDetails(lectureTable.getSelectedItem());
}
});
// delete lecture
deleteButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
deleteLecture(lectureTable.getSelectedItem());
}
});
// return to mainMenu
switchViewButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MainWindow.showPage(ImageListWindow.class);
}
});
/**
* Popup menu for the version table on the right side
*/
final PopupMenu pop = new PopupMenu(new ActionListener() {
public void actionPerformed(ActionEvent e) {
LectureSummary lecture = lectureTable.getSelectedItem();
if (lecture == null)
return;
if (e.getSource().equals(popupItemNew)) {
if (Gui.showMessageBox(me, "Um eine Veranstaltung zu erstellen, "
+ "müssen Sie ein Image auswählen. Zur Imageauswahl wechseln?",
MessageType.QUESTION_YESNO, LOGGER, null)) {
MainWindow.showPage(ImageListWindow.class);
}
}
if (e.getSource().equals(popupItemEdit)) {
openLectureDetails(lecture);
}
if (e.getSource().equals(popupItemDownload)) {
//TODO fix for students, who cannot see imageDetails somehow get filesize from server.
ImageDetailsRead image = ThriftActions.getImageDetails(
JOptionPane.getFrameForComponent(me), lecture.imageBaseId);
if (image != null) {
long versionSize = -1;
for (ImageVersionDetails version : image.getVersions()) {
if (version.versionId.equals(lecture.imageVersionId)) {
versionSize = version.fileSize;
break;
}
}
if (versionSize != -1) {
ThriftActions.initDownload(JOptionPane.getFrameForComponent(me),
lecture.imageVersionId, lecture.imageBaseId, image.virtId, image.osId,
versionSize, null);
}
}
}
if (e.getSource().equals(popupItemLinked)) {
ImageDetailsWindow.open(JOptionPane.getFrameForComponent(me), lecture.imageBaseId, null);
}
if (e.getSource().equals(popupItemDelete)) {
deleteLecture(lecture);
}
}
});
pop.addMenuItem(popupItemNew);
pop.addMenuItem(popupItemEdit);
pop.addMenuItem(popupItemLinked);
pop.addMenuItem(popupItemDownload);
pop.addSeparator();
pop.addMenuItem(popupItemDelete);
// finally the table listeners
lectureTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
processClick(e);
}
@Override
public void mouseReleased(MouseEvent e) {
processClick(e);
}
private void processClick(MouseEvent e) {
// left double click => open details
if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2 && Session.canListImages()) {
openLectureDetails(lectureTable.getSelectedItem());
return;
}
// else, check if we are a popup trigger
int r = lectureTable.rowAtPoint(e.getPoint());
if (r >= 0 && r < lectureTable.getRowCount()) {
// highlight the row and popup the menu
lectureTable.setRowSelectionInterval(r, r);
if (e.isPopupTrigger()) {
pop.show(e.getComponent(), e.getX(), e.getY());
}
} else {
lectureTable.clearSelection();
}
}
});
lectureTable.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_F5) {
refreshList(true);
}
}
});
lectureTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
LectureSummary item = lectureTable.getSelectedItem();
updateAvailableOptions(item);
}
});
if (Session.canListImages()) {
filterCbo.setSelectedItem(FilterType.OWN);
} else {
filterCbo.setSelectedItem(FilterType.ALL);
}
updateAvailableOptions(null);
// Some keyboard shortcuts
lectureTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "details");
lectureTable.getActionMap().put("details", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
editButton.doClick();
}
});
lectureTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
lectureTable.getActionMap().put("delete", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
deleteButton.doClick();
}
});
}
/**
* 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(LectureSummary lecture) {
boolean edit = LecturePerms.canEdit(lecture);
boolean admin = LecturePerms.canAdmin(lecture);
deleteButton.setEnabled(admin);
popupItemDelete.setEnabled(admin);
}
/**
* Opens the given lecture's details as a popup window
*/
private void openLectureDetails(final LectureSummary lecture) {
if (lecture == null)
return;
LectureDetailsWindow.open((JFrame) SwingUtilities.getWindowAncestor(me), lecture.getLectureId(),
new LectureUpdatedCallback() {
@Override
public void updated(boolean success) {
refreshList(success);
}
});
}
/**
* Deletes the given lecture
*/
private void deleteLecture(final LectureSummary lecture) {
if (lecture == null)
return;
ThriftActions.deleteLecture(JOptionPane.getFrameForComponent(me), lecture.getLectureId(),
new DeleteLectureCallback() {
@Override
public void deleted(boolean success) {
refreshList(success);
}
});
}
/**
* Applies the filter entered in the search field to the table
*/
private void applyFilterOnTable() {
if (filterCbo.getSelectedIndex() == -1)
return;
// Filter list we are about to fill
List<RowFilter<ListModel<LectureSummary>, Integer>> filters = new ArrayList<>();
// string for text in filter text field
if (searchFieldPattern != null) {
filters.add(filterSearchTerm);
}
// filters from the combobox
FilterType filterType = (FilterType) filterCbo.getSelectedItem();
lectureTable.setHighlightOwn(true);
switch (filterType) {
case ALL:
// no additional filters
break;
case OWN:
// filter for owner
filters.add(filterOwn);
break;
case ACTIVE:
// show only active lectures
filters.add(filterActive);
break;
case EDITABLE:
// show only editable lectures
filters.add(filterEditable);
break;
case EXPIRING:
// show only expiring lectures
filters.add(filterExpiring);
default:
break;
}
// for using multiple filters
RowFilter<ListModel<LectureSummary>, Integer> andFilters = RowFilter.andFilter(filters);
lectureTable.getRowSorter().setRowFilter(andFilters);
setLectureCountLabel(lectureTable.getRowCount());
}
private void refreshList(final boolean force) {
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
final List<LectureSummary> lectureList = LectureCache.get(force);
Gui.asyncExec(new Runnable() {
@Override
public void run() {
lectureTable.setData(lectureList, true);
setLectureCountLabel(lectureTable.getRowCount());
}
});
}
});
}
@Override
public boolean requestHide() {
return true;
}
@Override
public void requestShow() {
// en-/disable buttons when student
switchViewButton.setEnabled(Session.canListImages());
newButton.setEnabled(Session.canListImages());
popupItemNew.setEnabled(Session.canListImages());
popupItemLinked.setEnabled(Session.canListImages());
popupItemEdit.setEnabled(Session.canListImages());
editButton.setEnabled(Session.canListImages());
refreshList(false);
}
public void filterByImageBaseId(final String imageBaseId) {
RowFilter<ListModel<LectureSummary>, Integer> imageFilter = new RowFilter<ListModel<LectureSummary>, Integer>() {
public boolean include(Entry<? extends ListModel<LectureSummary>, ? extends Integer> entry) {
LectureSummary lecture = lectureTable.getModelRow(entry.getIdentifier());
return lecture.imageBaseId.equals(imageBaseId);
}
};
filterCbo.setSelectedIndex(-1);
searchTextField.setText("");
searchTextField.setEnabled(false);
lectureTable.getRowSorter().setRowFilter(imageFilter);
setLectureCountLabel(lectureTable.getRowCount());
}
}