package org.openslx.dozmod.gui.window; import java.awt.Color; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.swing.DefaultComboBoxModel; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JRadioButton; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.apache.log4j.Logger; import org.apache.thrift.TException; import org.openslx.bwlp.thrift.iface.ImageDetailsRead; import org.openslx.bwlp.thrift.iface.ImageSummaryRead; import org.openslx.bwlp.thrift.iface.ImageVersionDetails; import org.openslx.bwlp.thrift.iface.LecturePermissions; import org.openslx.bwlp.thrift.iface.LectureRead; import org.openslx.bwlp.thrift.iface.LectureWrite; import org.openslx.bwlp.thrift.iface.NetRule; import org.openslx.bwlp.thrift.iface.NetShare; 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.JCheckBoxTree.CheckChangeEvent; import org.openslx.dozmod.gui.control.JCheckBoxTree.CheckChangeEventListener; import org.openslx.dozmod.gui.control.LectureCustomPermissionManager.UserChangeEvent; import org.openslx.dozmod.gui.control.LectureCustomPermissionManager.UserChangeEventListener; import org.openslx.dozmod.gui.control.NetshareConfigurator.NetshareConfigurationChangeEvent; import org.openslx.dozmod.gui.control.NetshareConfigurator.NetshareConfigurationChangeEventListener; import org.openslx.dozmod.gui.control.RunscriptConfigurator.RunscriptConfigurationChangeEvent; import org.openslx.dozmod.gui.control.RunscriptConfigurator.RunscriptConfigurationChangeEventListener; import org.openslx.dozmod.gui.helper.DateTimeHelper; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.gui.helper.TextChangeListener; import org.openslx.dozmod.gui.helper.UiFeedback; import org.openslx.dozmod.gui.window.UserListWindow.UserAddedCallback; import org.openslx.dozmod.gui.window.layout.LectureDetailsWindowLayout; import org.openslx.dozmod.permissions.ImagePerms; import org.openslx.dozmod.permissions.LecturePerms; import org.openslx.dozmod.thrift.Session; import org.openslx.dozmod.thrift.ThriftActions; import org.openslx.dozmod.thrift.ThriftActions.DownloadCallback; import org.openslx.dozmod.thrift.ThriftActions.LectureMetaCallback; import org.openslx.dozmod.thrift.ThriftError; import org.openslx.dozmod.thrift.cache.UserCache; import org.openslx.dozmod.util.FormatHelper; import org.openslx.dozmod.util.MapHelper; import org.openslx.thrifthelper.ThriftManager; /** * Window to display and edit the details of a lecture */ @SuppressWarnings("serial") public class LectureDetailsWindow extends LectureDetailsWindowLayout implements UiFeedback { private static final Logger LOGGER = Logger.getLogger(LectureDetailsWindow.class); /** * Self-reference */ private final LectureDetailsWindow me = this; /** * Callback interface to refresh lecture list after changing lecture details */ public interface LectureUpdatedCallback { public void updated(boolean success); } /** * Callback to be called when changing lecture details on the server */ private LectureUpdatedCallback callback = null; /** * Lecture that this window shows the details of */ private LectureRead lecture = null; /** * The custom permissions of the lecture */ private Map customPermissions; /** * The original custom permissions as fetched from the server */ private Map originalCustomPermissions; /** * The original default permissions as fetched from the server */ private LecturePermissions originalDefaultPermissions; /** * Image, that the lecture is linked to. */ private ImageDetailsRead image = null; /** * Flag indicating a change in this lecture's linked image */ private boolean imageLinkChanged = false; /** * Flag indicating a change in this lecture's metadata */ private boolean metadataChanged = false; /** * Flag indicating a change in this lecture's permissions */ private boolean permissionsChanged = false; /** * Holder of the location information of this lecture */ private LocationInfo locationInfo = null; /** * Holder of the netrules/runscript of this lecture */ private List currentNetrules = null; private List originalNetrules = null; private String currentRunscript = null; private String originalRunscript = null; private List currentNetshares = null; private List originalNetshares = null; /** * Constructor * * @param modalParent parent of this popup window * @param callback function to be called when a lecture update occured */ public LectureDetailsWindow(Frame modalParent, LectureUpdatedCallback callback) { super(modalParent); // save callback this.callback = callback; setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { safeClose(); } }); btnLinkImage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ImageSummaryRead newImage = LectureChangeImage.open(me); if (newImage != null) { try { image = ThriftManager.getSatClient().getImageDetails(Session.getSatelliteToken(), newImage.imageBaseId); } catch (TException e1) { LOGGER.error("Failed to retrieve details of new image: ", e1); return; } lecture.imageBaseId = newImage.imageBaseId; lecture.imageVersionId = newImage.latestVersionId; fillVersionsCombo(); cboVersions.setEnabled(false); chkAutoUpdate.setSelected(true); imageLinkChanged = true; txtImageName.setText(newImage.getImageName()); reactToChange(); } } }); btnClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { safeClose(); } }); btnDownloadImage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { performImageDownload(); } }); chkAutoUpdate.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { cboVersions.setEnabled(!chkAutoUpdate.isSelected()); } }); btnChangeOwner.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { UserListWindow.open(me, new UserAddedCallback() { @Override public void userAdded(UserInfo user, UserListWindow window) { window.dispose(); if (Gui.showMessageBox(me, "Sind Sie sicher, dass sie die Besitzerrechte an " + "einen anderen Account übertragen wollen?", MessageType.QUESTION_YESNO, LOGGER, null)) setLectureOwner(user); } }, "Besitzer festlegen", lecture.ownerId); } }); final ActionListener changeReacter = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { reactToChange(); } }; ctlLocationSelector.getTree().addCheckChangeEventListener(new CheckChangeEventListener() { @Override public void checkStateChanged(CheckChangeEvent event) { reactToChange(); } }); for (JRadioButton btn : ctlLocationSelector.getButtons()) { btn.addActionListener(changeReacter); } final ActionListener updateDefaultPermissionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ctlPermissionManager.updateDefaultPermissions(chkCustomPermAdmin.isSelected(), chkCustomPermEdit.isSelected()); reactToChange(); } }; chkCustomPermAdmin.addActionListener(updateDefaultPermissionListener); chkCustomPermEdit.addActionListener(updateDefaultPermissionListener); ctlPermissionManager.getTable().addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { reactToChange(); } }); ctlPermissionManager.addUserChangeEventListener(new UserChangeEventListener() { @Override public void stateChanged(UserChangeEvent event) { reactToChange(); } }); chkCustomPermAdmin.addActionListener(changeReacter); chkCustomPermEdit.addActionListener(changeReacter); btnNetrules.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { List newNetrules = LectureNetrulesWindow.open(me, currentNetrules); if (newNetrules != null) currentNetrules = newNetrules; reactToChange(); } }); final TextChangeListener docListener = new TextChangeListener() { @Override public void changed() { reactToChange(); } }; txtTitle.getDocument().addDocumentListener(docListener); txtDescription.getDocument().addDocumentListener(docListener); ctlRunscriptConfigurator.addRunscriptConfigurationChangeEventListener(new RunscriptConfigurationChangeEventListener() { @Override public void stateChanged(RunscriptConfigurationChangeEvent event) { reactToChange(); } }); ctlNetshareConfigurator.addNetshareConfigurationChangeEventListener(new NetshareConfigurationChangeEventListener() { @Override public void stateChanged(NetshareConfigurationChangeEvent event) { reactToChange(); } }); // Comboboxes final ItemListener comboItemListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { reactToChange(); } } }; cboVersions.addItemListener(comboItemListener); // Listener to detect changes in checkboxes final ActionListener actionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { reactToChange(); } }; ChangeListener changeListener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { reactToChange(); } }; chkAutoUpdate.addActionListener(actionListener); chkIsExam.addActionListener(actionListener); chkHasInternetAccess.addActionListener(actionListener); chkHasUsbAccess.addActionListener(actionListener); chkIsActive.addActionListener(actionListener); dtpStartDate.addActionListener(actionListener); dtpEndDate.addActionListener(actionListener); spnStartTime.addChangeListener(changeListener); spnEndTime.addChangeListener(changeListener); ctlLdapFilterConfigurator.addLdapFilterListTableContentConfigurationChangeEventListener(changeListener); // save default color of date/time stuff to reset the background later dateTimeTextColor = dtpStartDate.getForeground(); // last step, the save button btnSaveChanges.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { saveChanges(); } }); // disable save button btnSaveChanges.setEnabled(false); // wait for the image to be loaded before (potentially) enabling fields toggleEditable(false); } /** * Sets the lecture to show the details of by setting the 'lecture' and * 'image' * members to its metadata. This method will fetch the information from the * sat * * @param lectureId the id of the lecture to be displayed */ public void setLecture(final String lectureId) { ThriftActions.getLectureAndImageDetails(JOptionPane.getFrameForComponent(me), lectureId, new LectureMetaCallback() { @Override public void fetchedLectureAndImageDetails(LectureRead lectureDetails, ImageDetailsRead imageDetails) { synchronized (me) { lecture = lectureDetails; image = imageDetails; if (lecture != null) { customPermissions = ThriftActions.getLecturePermissions( JOptionPane.getFrameForComponent(me), lecture.lectureId); } fillDetails(); } } }); } /** * Internal callback function when we received the lecture's details from the server */ private void fillDetails() { if (lecture == null) { txtTitle.setText("-"); lblTitleInfo.setText("-"); toggleEditable(false); return; } if (image == null) { txtImageName.setText("-"); lblImageNameInfo.setText("-"); } else { txtImageName.setText(image.getImageName()); lblImageNameInfo.setText(image.getImageName()); } // remember original netrules and runscript originalNetrules = lecture.networkExceptions != null ? lecture.networkExceptions : new ArrayList(); originalRunscript = lecture.runscript != null ? lecture.runscript : new String(""); originalNetshares = lecture.networkShares != null ? new ArrayList(lecture.networkShares) : new ArrayList(); currentNetrules = originalNetrules; currentRunscript = originalRunscript; currentNetshares = originalNetshares; // remember default permissions if (lecture.defaultPermissions != null) { originalDefaultPermissions = new LecturePermissions(lecture.defaultPermissions); } // remember custom permissions if (customPermissions != null) { // need a deep copy of the permission map to be able to check for changes after ImageCustomPermissionWindow if (originalCustomPermissions == null) originalCustomPermissions = new HashMap(); else originalCustomPermissions.clear(); // fill it for (Entry entry : customPermissions.entrySet()) { originalCustomPermissions.put(entry.getKey(), new LecturePermissions(entry.getValue())); } } // init permission info ctlPermissionManager.initPanel(customPermissions, lecture.defaultPermissions, lecture.ownerId); chkCustomPermAdmin.setSelected(lecture.defaultPermissions.admin); chkCustomPermEdit.setSelected(lecture.defaultPermissions.edit); // init location info locationInfo = new LocationInfo(lecture.locationIds, lecture.limitToLocations); ctlLocationSelector.setOnlyInSelection(locationInfo.limitToLocations); ctlLocationSelector.setSelectedLocationsAsIds(locationInfo.locationList); // init advanced info ctlRunscriptConfigurator.setState(lecture.runscript); ctlNetshareConfigurator.setState(lecture.networkShares); ctlLdapFilterConfigurator.setState(lecture.ldapFilters); txtTitle.setText(lecture.getLectureName()); lblTitleInfo.setText(lecture.getLectureName()); txtDescription.setText(lecture.getDescription()); lblOwner.setUser(UserCache.find(lecture.getOwnerId())); lblOwnerInfo.setUser(UserCache.find(lecture.getOwnerId())); lblUpdater.setUser(UserCache.find(lecture.getUpdaterId())); lblCreateTime.setText(FormatHelper.longDate(lecture.getCreateTime())); lblUpdateTime.setText(FormatHelper.longDate(lecture.getUpdateTime())); lblStartTime.setText(FormatHelper.longDate(lecture.getStartTime())); lblEndTime.setText(FormatHelper.longDate(lecture.getEndTime())); txtId.setText(lecture.getLectureId()); chkIsActive.setSelected(lecture.isEnabled); chkHasInternetAccess.setSelected(lecture.hasInternetAccess); chkHasUsbAccess.setSelected(lecture.hasUsbAccess); chkIsExam.setSelected(lecture.isExam); chkAutoUpdate.setSelected(lecture.autoUpdate); cboVersions.setEnabled(!lecture.autoUpdate); lblUseCount.setText(Integer.toString(lecture.useCount)); fillVersionsCombo(); Calendar startCal = Calendar.getInstance(); startCal.setTime(new Date(lecture.getStartTime() * 1000l)); dtpStartDate.getModel().setDate(startCal.get(Calendar.YEAR), startCal.get(Calendar.MONTH), startCal.get(Calendar.DATE)); spnStartTime.getModel().setValue(startCal.getTime()); Calendar endCal = Calendar.getInstance(); endCal.setTime(new Date(lecture.getEndTime() * 1000l)); dtpEndDate.getModel().setDate(endCal.get(Calendar.YEAR), endCal.get(Calendar.MONTH), endCal.get(Calendar.DATE)); spnEndTime.getModel().setValue(endCal.getTime()); // now enable the tabs the user can see given its permissions toggleEditable(true); // and always switch to the "About" tab pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Übersicht")); setVisible(true); } /** * Helper to fill the combobox with the versions of the image. The list will * be sorted by creation timestamp */ private void fillVersionsCombo() { List versions; if (image == null) { versions = new ArrayList<>(0); } else { versions = image.getVersions(); } // version combo for (Iterator it = versions.iterator(); it.hasNext();) { ImageVersionDetails version = it.next(); if (!version.isValid && !lecture.imageVersionId.equals(version.versionId)) { it.remove(); } } // sort versions by createtime Collections.sort(versions, new Comparator() { public int compare(ImageVersionDetails o1, ImageVersionDetails o2) { return -Long.compare(o1.getCreateTime(), o2.getCreateTime()); } }); cboVersions.setModel(new DefaultComboBoxModel( versions.toArray(new ImageVersionDetails[versions.size()]))); cboVersions.setSelectedItem(new ImageVersionDetails(lecture.getImageVersionId(), 0, 0, 0, null, true, true, true, null)); } /** * Sets the lecture's owner to the given user * * @param user UserInfo representation of the new owner */ private void setLectureOwner(final UserInfo user) { if (!ThriftActions.setLectureOwner(JOptionPane.getFrameForComponent(this), lecture.getLectureId(), user)) { return; } // success Gui.showMessageBox(me, "Besitzrechte übertragen an " + FormatHelper.userName(user), MessageType.INFO, null, null); toggleEditable(false); String lectureId = lecture.getLectureId(); synchronized (me) { image = null; lecture = null; } setLecture(lectureId); } /** * Triggers the download of the currently used image version of the lecture */ private void performImageDownload() { if (image == null) { Gui.showMessageBox(this, "VM ungültig.", MessageType.ERROR, null, null); return; } btnDownloadImage.setEnabled(false); long versionSize = 0; for (ImageVersionDetails version : image.versions) { if (version.versionId.equals(lecture.imageVersionId)) { if (!version.isValid) { Gui.showMessageBox(this, "Ungültige VM-Version gewählt", MessageType.ERROR, null, null); return; } versionSize = version.fileSize; break; } } if (versionSize == 0) { Gui.showMessageBox(this, "Fehler bei der Abfrage der Größe des VM-Abbildes.", MessageType.ERROR, null, null); return; } ThriftActions.initDownload(JOptionPane.getFrameForComponent(this), lecture.imageVersionId, image.imageName, image.virtId, image.osId, versionSize, new DownloadCallback() { @Override public void downloadInitialized(boolean success) { if (!success) { Gui.asyncExec(new Runnable() { @Override public void run() { btnDownloadImage.setEnabled(true); } }); } } }); } /** * Checks whether the user changed any fields of the image details and * enables the save button if so. */ private void reactToChange() { // before checks we need to update the local objects holding the information of the "widgets" // update the location information locationInfo = new LocationInfo(ctlLocationSelector.getSelectedLocationsAsIds(), ctlLocationSelector.getOnlyInSelection()); // update the custom permissions customPermissions = ctlPermissionManager.updatePermissionReferences(); // NOTE: AdvancedConfiguration stuff will only get checked when clicking "Save" since // checking for rules syntax while the user is still typing does not make much sense... // now we can check for changes metadataChanged = reactToChangeInternal(); permissionsChanged = MapHelper.hasChanged(originalCustomPermissions, customPermissions); btnSaveChanges.setEnabled(metadataChanged || permissionsChanged); } /** * Checks whether the user changed any fields of the image details and * enables the save button if so. */ private boolean reactToChangeInternal() { if (lecture == null) return false; boolean changed = false; // mandatory fields checks if (txtTitle.getText().isEmpty()) { pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Allgemein")); lblError.setText("Kein Veranstaltungsname gesetzt!"); return false; } if (txtDescription.getText().isEmpty()) { pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Allgemein")); lblError.setText("Keine Beschreibung angegeben!"); return false; } // version checkbox changed? ImageVersionDetails currentVersion = cboVersions.getItemAt(cboVersions.getSelectedIndex()); if (currentVersion == null) { pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Allgemein")); lblError.setText("Keine Version ausgewählt!"); return false; } // Date stuff Date start = DateTimeHelper.getDateFrom(dtpStartDate, spnStartTime); Date end = DateTimeHelper.getDateFrom(dtpEndDate, spnEndTime); if (!isPeriodValid(start, end, false) && dateHasChanged()) { pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Allgemein")); lblError.setText("Ungültiger Zeitraum!"); return false; } // runscript stuff String newState = ctlRunscriptConfigurator.getState(); if (newState == null) { // script extension was missing from the user input. // feedback happens in the configurator, just switch to the tab. pnlTabs.setSelectedIndex(pnlTabs.indexOfTab("Startskript")); return false; } else { currentRunscript = newState; } // netshare stuff List newNetshareList = ctlNetshareConfigurator.getState(); if (newNetshareList != null) { currentNetshares = newNetshareList; } // done with mandatory checks, remove error message lblError.setText(null); // TODO: Refactor change detection and error display so you don't lose your mind when // trying to work with it. return true; /* // check for changes in all fields changed = !txtTitle.getText().equals(lecture.getLectureName()) || !txtDescription.getText().equals(lecture.getDescription()) || !currentVersion.getVersionId().equals(lecture.getImageVersionId()) || (DateTimeHelper.getDateFrom(dtpStartDate, spnStartTime).getTime() / 1000L) != lecture.getStartTime() || (DateTimeHelper.getDateFrom(dtpEndDate, spnEndTime).getTime() / 1000L) != lecture.getEndTime() || chkAutoUpdate.isSelected() != lecture.autoUpdate || chkIsExam.isSelected() != lecture.isExam || chkHasInternetAccess.isSelected() != lecture.hasInternetAccess || chkHasUsbAccess.isSelected() != lecture.hasUsbAccess || chkIsActive.isSelected() != lecture.isEnabled || !lecture.defaultPermissions.equals(originalDefaultPermissions) || (locationInfo != null && lecture.locationIds != null && !lecture.locationIds.equals(locationInfo.locationList)) || (locationInfo != null && lecture.limitToLocations != locationInfo.limitToLocations) || (currentNetrules != null && !currentNetrules.equals(originalNetrules)) || (currentRunscript != null && !currentRunscript.equals(originalRunscript)) || (currentNetshares != null && !currentNetshares.equals(originalNetshares)) || imageLinkChanged; return changed; */ } /** * Triggers the saving of the changes of this lecture * And inform the callback function about the outcome */ private void saveChanges() { boolean saved = saveChangesInternal(); callback.updated(saved); if (saved) { dispose(); } else { btnSaveChanges.setEnabled(true); } } /** * Internal helper actually saving the changes to the satellite * * @return true if saving succeeded, false otherwise. */ private boolean saveChangesInternal() { // check, whether autoupdate is selected and choose version accordingly if (image != null) { lecture.imageVersionId = chkAutoUpdate.isSelected() ? image.latestVersionId : cboVersions.getItemAt(cboVersions.getSelectedIndex()).versionId; } metadataChanged |= (currentNetrules != lecture.networkExceptions || currentRunscript != lecture.runscript || currentNetshares != lecture.networkShares); // now check if we need to push a new LectureWrite if (metadataChanged) { // first build the LectureWrite from the GUI fields final LectureWrite metadata = new LectureWrite(txtTitle.getText(), txtDescription.getText(), lecture.getImageVersionId(), chkAutoUpdate.isSelected(), chkIsActive.isSelected(), DateTimeHelper.getDateFrom(dtpStartDate, spnStartTime).getTime() / 1000L, DateTimeHelper.getDateFrom(dtpEndDate, spnEndTime).getTime() / 1000L, currentRunscript, null, chkIsExam.isSelected(), chkHasInternetAccess.isSelected(), // TODO USBACCESS lecture.getDefaultPermissions(), locationInfo.locationList, locationInfo.limitToLocations, // TODO: coming "false" is Location related false, chkHasUsbAccess.isSelected()); metadata.setNetworkExceptions(currentNetrules); metadata.setNetworkShares(currentNetshares); metadata.setLdapFilters(ctlLdapFilterConfigurator.getState()); // now trigger the actual action try { ThriftManager.getSatClient().updateLecture(Session.getSatelliteToken(), lecture.getLectureId(), metadata); metadataChanged = false; LOGGER.info("Successfully save new metadata"); } catch (TException e) { ThriftError.showMessage(JOptionPane.getFrameForComponent(this), LOGGER, e, "Fehler beim Updaten der Veranstaltung!"); callback.updated(false); return false; } } if (permissionsChanged) { try { ThriftManager.getSatClient().writeLecturePermissions(Session.getSatelliteToken(), lecture.lectureId, customPermissions); permissionsChanged = false; LOGGER.info("Successfully save new permissions"); } catch (TException e) { ThriftError.showMessage(JOptionPane.getFrameForComponent(this), LOGGER, e, "Fehler beim Übertragen der Berechtigungen!"); callback.updated(true); return false; } } return true; } /** * Checks if the given start and end date represent a valid time period. * This is the case, if start < end and if current time < end * * @param start date of the period to check * @param end date of the period to check * @param feedback true if the user should be shown feedback, false * otherwise * @return true if the period is valid, false otherwise */ private boolean isPeriodValid(final Date start, final Date end, boolean feedback) { if (start == null || end == null) return false; // analyse time stuff to see if its valid if (start.after(end)) { dtpStartDate.setForeground(Color.red); if (feedback) Gui.showMessageBox(me, "Start der Veranstaltung ist nach dem Enddatum!", MessageType.ERROR, LOGGER, null); } else { dtpStartDate.setForeground(dateTimeTextColor); return true; } return false; } /** * Check whether the date has been changed * * @return true if it has changed, false otherwise */ private boolean dateHasChanged() { return (DateTimeHelper.getDateFrom(dtpStartDate, spnStartTime).getTime() / 1000L) != lecture.getStartTime() || (DateTimeHelper.getDateFrom(dtpEndDate, spnEndTime).getTime() / 1000L) != lecture.getEndTime(); } /** * Enables/Disables the tabs based on the given flag 'editable'. * * @param editable when true, will enable the tabs if the user is allowed to see them. * If false, this will disable all tabs but the first tab "About". */ protected void toggleEditable(boolean editable) { // if we don't have a lecture and an image set, just disable editable &= (LecturePerms.canEdit(lecture)); // enable the standard tabs that are always enabled pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Allgemein"), editable); pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Berechtigungen"), editable && LecturePerms.canAdmin(lecture)); // enable the other tabs that might have been added to the panel (depends on API version) if (pnlTabs.indexOfTab("Beschränkungen") != -1) { pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Beschränkungen"), editable); } if (pnlTabs.indexOfTab("Raumauswahl") != -1) { pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Raumauswahl"), editable); } if (pnlTabs.indexOfTab("Startskript") != -1) { pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Startskript"), editable); } if (pnlTabs.indexOfTab("Netzlaufwerke") != -1) { pnlTabs.setEnabledAt(pnlTabs.indexOfTab("Netzlaufwerke"), true); } btnChangeOwner.setEnabled(LecturePerms.canAdmin(lecture)); btnDownloadImage.setEnabled(ImagePerms.canDownload(image)); } /** * Opens a new LectureDetailsWindow showing the details of the * lecture with ID = lectureId * * @param modalParent parent of this window * @param lectureId id of the lecture to set the details of */ public static void open(Frame modalParent, String lectureId, LectureUpdatedCallback callback) { LectureDetailsWindow win = new LectureDetailsWindow(modalParent, callback); win.setLecture(lectureId); win.setVisible(true); } @SuppressWarnings("deprecation") @Override public void show() { if (!isVisible()) { pack(); MainWindow.centerShell(this); } super.show(); } /* ******************************************************************************* * * UIFeedback implementation * ********************************************************************************/ @Override public boolean wantConfirmQuit() { return metadataChanged || permissionsChanged; } @Override public void escapePressed() { // Also ask if applicable safeClose(); } /* * Safe close helper: checks if we have unsaved work and prompt the user for * confirmation if so */ private void safeClose() { if ((metadataChanged || permissionsChanged) && !Gui.showMessageBox(me, "Änderungen werden verworfen, wollen Sie wirklich schließen?", MessageType.QUESTION_YESNO, null, null)) return; synchronized(me) { lecture = null; image = null; } dispose(); } }