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.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 org.apache.log4j.Logger;
import org.apache.thrift.TException;
import org.openslx.bwlp.thrift.iface.ImageBaseWrite;
import org.openslx.bwlp.thrift.iface.ImageDetailsRead;
import org.openslx.bwlp.thrift.iface.ImagePermissions;
import org.openslx.bwlp.thrift.iface.ImageSummaryRead;
import org.openslx.bwlp.thrift.iface.ImageVersionDetails;
import org.openslx.bwlp.thrift.iface.LectureSummary;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.ShareMode;
import org.openslx.bwlp.thrift.iface.UserInfo;
import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.changemonitor.AbstractControlWrapper;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor;
import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor.TextNotEmptyConstraint;
import org.openslx.dozmod.gui.helper.DateTimeHelper;
import org.openslx.dozmod.gui.helper.ExpiryDateChooser;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.PopupMenu;
import org.openslx.dozmod.gui.helper.UiFeedback;
import org.openslx.dozmod.gui.window.UserListWindow.UserAddedCallback;
import org.openslx.dozmod.gui.window.layout.ImageDetailsWindowLayout;
import org.openslx.dozmod.gui.wizard.ImageUpdateWizard;
import org.openslx.dozmod.gui.wizard.LectureWizard;
import org.openslx.dozmod.permissions.ImagePerms;
import org.openslx.dozmod.thrift.ImageDetailsActions;
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.ImageMetaCallback;
import org.openslx.dozmod.thrift.ThriftError;
import org.openslx.dozmod.thrift.cache.LectureCache;
import org.openslx.dozmod.thrift.cache.MetaDataCache;
import org.openslx.dozmod.thrift.cache.UserCache;
import org.openslx.dozmod.util.DesktopEnvironment;
import org.openslx.dozmod.util.FormatHelper;
import org.openslx.sat.thrift.version.Feature;
import org.openslx.thrifthelper.Comparators;
import org.openslx.thrifthelper.TConst;
import org.openslx.thrifthelper.ThriftManager;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
import org.openslx.util.ThriftUtil;
import org.openslx.util.Util;
/**
* Window for displaying and editing the details of an image.
*/
@SuppressWarnings("serial")
public class ImageDetailsWindow extends ImageDetailsWindowLayout implements UiFeedback {
private static final Logger LOGGER = Logger.getLogger(ImageDetailsWindow.class);
/**
* Self-reference
*/
private final ImageDetailsWindow me = this;
/**
* Action handler proxying thrift calls to differentiate between local and
* published image mode
*/
private final ImageDetailsActions actionHandler;
/**
* Callback interface to refresh image list after changing image details
*/
public interface ImageUpdatedCallback {
public void updated();
}
/**
* Callback instance
*/
private ImageUpdatedCallback callback = null;
/**
* Image that this window shows the details of
*/
private ImageDetailsRead image = null;
/**
* The current state of custom permissions of the image
*/
private Map<String, ImagePermissions> customPermissions;
/**
* Did the user have admin rights due to default permissions?
*/
private boolean adminRightsFromDefaultPermissions;
/**
* Popup menu items
*/
private final JMenuItem mnuNewLecture = new JMenuItem("Neue Veranstaltung");
private final JMenuItem mnuDownload = new JMenuItem("Download");
private final JMenuItem mnuVmConfig = new JMenuItem("VM-Konfiguration");
private final JMenuItem mnuDelete = new JMenuItem("Löschen");
private final JMenuItem mnuExtendExpiryDate = new JMenuItem("Ablaufzeitpunkt verlängern");
private DialogChangeMonitor changeMonitor;
private AbstractControlWrapper<?> changeListenerPermissions;
/**
* Constructor
*
* @param modalParent parent of this popup window
* @param callback callback to be called when the image details have changed
*/
public ImageDetailsWindow(Frame modalParent, ImageUpdatedCallback callback,
ImageDetailsActions actionHandler) {
super(modalParent);
this.callback = callback;
this.actionHandler = actionHandler;
// Set up change monitor
changeMonitor = new DialogChangeMonitor(new DialogChangeMonitor.Callback() {
@Override
public void validityChanged(String errorMessage) {
lblError.setText(errorMessage);
btnSaveChanges.setEnabled(changeMonitor.isValid() && changeMonitor.wasEverModified());
LOGGER.info("Valid: " + changeMonitor.isValid());
}
@Override
public void modificationChanged() {
btnSaveChanges.setEnabled(changeMonitor.isValid() && changeMonitor.wasEverModified());
LOGGER.info("Changed: " + changeMonitor.isCurrentlyModified());
}
});
// Hook when user presses X (top right)
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
safeClose();
}
});
/**
* Button listeners
*/
btnClose.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
safeClose();
}
});
btnSaveChanges.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveChanges();
}
});
btnUpdateImage.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// FIXME: This will always discard all changes even if you cancel right away
new ImageUpdateWizard(me, image).setVisible(true);
refresh(true);
}
});
btnUploadToMaster.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
uploadToMaster();
}
});
btnShowLinkingLectures.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (safeClose()) {
LectureListWindow page = MainWindow.showPage(LectureListWindow.class);
page.filterByImageBaseId(image.imageBaseId);
}
}
});
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 Benutzer übertragen wollen?",
MessageType.QUESTION_YESNO, LOGGER, null))
setImageOwner(user);
}
}, "Besitzer festlegen", image.ownerId);
}
});
tblVersions.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
/**
* Popup menu for the version table on the right side
*/
final PopupMenu pop = new PopupMenu(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ImageVersionDetails selected = tblVersions.getSelectedItem();
if (selected == null)
return;
if (e.getSource().equals(mnuNewLecture)) {
ImageSummaryRead summary = new ImageSummaryRead();
summary.setImageName(image.getImageName()); // Maybe create a helper class/function some day that transforms all fields
new LectureWizard(me, summary, selected.getVersionId()).setVisible(true);
}
if (e.getSource().equals(mnuDownload)) {
performImageDownload(selected);
}
if (e.getSource().equals(mnuDelete)) {
deleteVersions(tblVersions.getSelectedItems());
}
if (e.getSource().equals(mnuVmConfig)) {
editVmConfig(selected);
}
if (e.getSource().equals(mnuExtendExpiryDate)) {
extendVersionExpiry(tblVersions.getSelectedItems());
}
}
});
pop.addMenuItem(mnuNewLecture);
pop.addMenuItem(mnuDownload);
if (Session.isLectureRestrictionsSupported())
pop.addMenuItem(mnuVmConfig);
pop.addSeparator();
pop.addMenuItem(mnuDelete);
if (Session.canExtendImageExpiry()) {
pop.addSeparator();
pop.addMenuItem(mnuExtendExpiryDate);
}
// keyboard shortcut
tblVersions.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "delete");
tblVersions.getActionMap().put("delete", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
if (ImagePerms.canEdit(image)) {
deleteVersions(tblVersions.getSelectedItems());
}
}
});
/**
* Mouse adapter for the version table
*/
final MouseAdapter ma = new MouseAdapter() {
@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 = tblVersions.rowAtPoint(e.getPoint());
// is the click event on an already selected row?
boolean alreadySelectedRow = false;
for (int i : tblVersions.getSelectedRows()) {
if (i == mouseRowIndex) {
alreadySelectedRow = true;
break;
}
}
if (mouseRowIndex >= 0 && mouseRowIndex < tblVersions.getRowCount()
&& SwingUtilities.isRightMouseButton(e)) {
// select row if it wasn't in selection before
if (!alreadySelectedRow) {
tblVersions.setRowSelectionInterval(mouseRowIndex, mouseRowIndex);
}
if (e.isPopupTrigger()) {
boolean multiSelection = tblVersions.getSelectedRowCount() != 1;
ImageVersionDetails selectedVersion = tblVersions.getSelectedItem();
mnuNewLecture.setEnabled(
!multiSelection && selectedVersion.isValid && ImagePerms.canLink(image));
mnuDownload.setEnabled(!multiSelection && ImagePerms.canDownload(image));
mnuVmConfig.setEnabled(!multiSelection && selectedVersion.isValid
&& ImagePerms.canEdit(image) && (image.shareMode == ShareMode.LOCAL
|| image.shareMode == ShareMode.PUBLISH));
mnuDelete.setEnabled(ImagePerms.canEdit(image));
mnuExtendExpiryDate.setEnabled(!multiSelection && (selectedVersion.isValid
|| Session.hasFeature(Feature.EXTEND_EXPIRED_VM)));
pop.show(e.getComponent(), e.getX(), e.getY());
}
}
}
};
scpVersions.addMouseListener(ma);
tblVersions.addMouseListener(ma);
// add controls to change monitor to handle user actions
changeMonitor.add(txtTitle).addConstraint(new TextNotEmptyConstraint("Name darf nicht leer sein"));
changeMonitor.add(txtDescription)
.addConstraint(new TextNotEmptyConstraint("Beschreibung darf nicht leer sein"));
changeMonitor.add(txtTags);
changeMonitor.addFixedCombo(cboOperatingSystem, Comparators.operatingSystem)
.addConstraint(new DialogChangeMonitor.ValidationConstraint<OperatingSystem>() {
public String checkStateValid(OperatingSystem userInput) {
if (userInput != null && MetaDataCache.getOsById(userInput.osId) != null) // validating OS coming from the cache makes no sense?
return null;
return "Ungültiges Betriebssystem ausgewählt!";
}
});
changeMonitor.addFixedCombo(cboShareMode, null)
.addConstraint(new DialogChangeMonitor.ValidationConstraint<ShareMode>() {
public String checkStateValid(ShareMode userInput) {
if (userInput != null)
return null;
return "Ungültiges Betriebssystem ausgewählt!";
}
});
changeMonitor.add(chkIsTemplate);
changeMonitor.add(chkDefaultPermLink);
changeMonitor.add(chkDefaultPermDownload);
changeMonitor.add(chkDefaultPermEdit);
changeMonitor.add(chkDefaultPermAdmin);
changeListenerPermissions = changeMonitor.add(ctlImagePermissionConfigurator);
// update default permissions hook for the permission configurator to apply to newly added users
final ItemListener updateDefaultPermissionsListener = new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getSource() == chkDefaultPermLink)
image.defaultPermissions.link = chkDefaultPermLink.isSelected();
if (e.getSource() == chkDefaultPermDownload)
image.defaultPermissions.download = chkDefaultPermDownload.isSelected();
if (e.getSource() == chkDefaultPermEdit)
image.defaultPermissions.edit = chkDefaultPermEdit.isSelected();
if (e.getSource() == chkDefaultPermAdmin)
image.defaultPermissions.admin = chkDefaultPermAdmin.isSelected();
}
};
chkDefaultPermLink.addItemListener(updateDefaultPermissionsListener);
chkDefaultPermDownload.addItemListener(updateDefaultPermissionsListener);
chkDefaultPermEdit.addItemListener(updateDefaultPermissionsListener);
chkDefaultPermAdmin.addItemListener(updateDefaultPermissionsListener);
/**
* Initial state of GUI elements
*/
setFocusable(true);
btnSaveChanges.setEnabled(false);
txtVersion.setEditable(false);
txtId.setEditable(false);
chkIsTemplate.setEnabled(Session.isSuperUser());
btnUploadToMaster.setVisible(actionHandler.isImagePublishSupported());
makeEditable(false);
// TODO finish ShareMode in server
cboShareMode.setEnabled(false);
}
private void editVmConfig(final ImageVersionDetails selected) {
QuickTimer.scheduleOnce(new Task() {
ByteBuffer machineDescription = null;
@Override
public void fire() {
try {
machineDescription = ThriftManager.getSatClient()
.getImageVersionVirtConfig(Session.getSatelliteToken(), selected.versionId);
} catch (TException e) {
LOGGER.error("Failed to retrieve virtualizer config for image version " + "'"
+ image.latestVersionId + ", see trace: ", e);
return;
}
Gui.asyncExec(new Runnable() {
@Override
public void run() {
if (machineDescription == null) {
Gui.showMessageBox("Konnte VM-Konfiguration nicht abrufen.", MessageType.ERROR,
LOGGER, null);
return;
}
String tmp = ThriftUtil.byteBufferToString(machineDescription);
if (TConst.VIRT_QEMU.equals(image.virtId)) {
VirtConfigEditorWindow.open(me, actionHandler, selected.versionId,
ThriftUtil.byteBufferToString(machineDescription), tmp);
} else {
VirtDropDownConfigEditorWindow.open(me, actionHandler, selected.versionId,
machineDescription);
}
}
});
}
});
}
/********************************************************************************
*
* Helper triggering the actual thrift calls
*
********************************************************************************/
/**
* Sets the image to the given imageBaseId. This will also trigger fill()
* which will set the image details fields to the values represented by this
* image.
*
* @param imageBaseId the id of the image to be displayed
*/
public void setImage(final String imageBaseId) {
// Just prime the cache...
MetaDataCache.getOperatingSystems();
MetaDataCache.getVirtualizers();
final ImageMetaCallback callback = new ImageMetaCallback() {
@Override
public void fetchedImageDetails(ImageDetailsRead imageDetails,
Map<String, ImagePermissions> permissions) {
if (imageDetails == null) {
return;
}
if (permissions == null) {
permissions = new HashMap<>();
}
synchronized (me) {
image = imageDetails;
customPermissions = permissions;
}
fillDetails();
}
};
actionHandler.getImageDetails(imageBaseId, callback);
}
/**
* Sets the owner of the selected image to the given user.
*
* @param user UserInfo to set the owner to
*/
private void setImageOwner(final UserInfo user) {
if (!actionHandler.setImageOwner(image.getImageBaseId(), user)) {
return;
}
Gui.showMessageBox(me, "Besitzrechte übertragen an " + FormatHelper.userName(user), MessageType.INFO,
null, null);
makeEditable(false);
refresh(true);
}
/**
* Called by the "Publish" button. Tries to upload that image to the
* masterserver.
*/
private void uploadToMaster() {
// 04.2018: bail if we the user tries to publish a non-vmware image.
if (Session.hasFeature(Feature.MULTIPLE_HYPERVISORS) && !TConst.VIRT_VMWARE.equals(image.virtId)) {
Gui.showMessageBox(
MetaDataCache.getVirtualizerById(image.virtId).virtName
+ " ist derzeit nicht für den öffentlichen Austausch freigegeben.",
MessageType.ERROR, null, null);
return;
}
if (changeMonitor.isCurrentlyModified()) {
if (Gui.showMessageBox("Sie haben unspeicherte Änderungen, wollen Sie diese erst speichern?",
MessageType.QUESTION_YESNO, null, null)) {
if (!saveChangesInternal()) {
return;
}
}
}
// let the user confirm or abort
if (!Gui.showMessageBox("Wollen Sie diese VM wirklich landesweit veröffentlichen?",
MessageType.QUESTION_YESNO, null, null))
return;
// start upload to masterserver
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
final String transferId;
try {
transferId = ThriftManager.getSatClient().publishImageVersion(Session.getSatelliteToken(),
image.latestVersionId);
} catch (TException e1) {
ThriftError.showMessage(me, LOGGER, e1,
"Upload der VM auf den Masterserver fehlgeschlagen."
+ " Prüfen Sie, ob Sie bei der Registrierung dem landesweiten VM-Austausch zugestimmt haben.\n"
+ " Sie können dies hier überprüfen:\n"
+ DesktopEnvironment.Link.REGISTER_BWIDM.uri.toString() + "\n\n");
return;
}
Gui.asyncExec(new Runnable() {
@Override
public void run() {
MainWindow.addPassiveTransfer(transferId, image.imageName, true);
// Inform user
Gui.showMessageBox(ImageDetailsWindow.this,
"Die Übertragung läuft direkt zwischen Satellitenserver und"
+ " dem Zentral-Server in Freiburg.\n"
+ "Wenn Sie die bwLehrpool-Suite schließen, wird der Transfer trotzdem"
+ "weiterlaufen.",
MessageType.INFO, null, null);
}
});
}
});
}
/**
* Called by the "Save" button, tries to save the changes internally and
* then react based depending on the outcome of the save
*/
private void saveChanges() {
boolean saved = saveChangesInternal();
// if there was nothing to save, saved would be true from the above call
// however we wouldn't even get to saving if nothing was changed, so its fine
if (saved) {
if (callback != null)
callback.updated();
dispose();
} else {
btnSaveChanges.setEnabled(true);
}
}
/**
* Helper to only save the changes, nothing else. Updating GUI elements is
* done by saveChanges()
*
* @return false if any try to save changes failed, true otherwise
*/
private boolean saveChangesInternal() {
// Special case: User has admin rights through default permissions
// -> user removes default admin permissions
// -> first save custom permissions, then the rest (including default permissions)
if (adminRightsFromDefaultPermissions && changeListenerPermissions.isCurrentlyChanged()) {
if (!saveCustomPermissions()) {
return false;
}
changeListenerPermissions.reset();
}
// first build the ImageBaseWrite from the GUI fields
final ImageBaseWrite ibw = new ImageBaseWrite(txtTitle.getText(), txtDescription.getText(),
cboOperatingSystem.getItemAt(cboOperatingSystem.getSelectedIndex()).osId, image.virtId,
chkIsTemplate.isSelected(),
new ImagePermissions(image.defaultPermissions.link, image.defaultPermissions.download,
image.defaultPermissions.edit, image.defaultPermissions.admin),
cboShareMode.getItemAt(cboShareMode.getSelectedIndex()));
try {
actionHandler.updateImageBase(image.getImageBaseId(), ibw);
LOGGER.info("Successfully saved new metadata");
} catch (TException e) {
ThriftError.showMessage(me, LOGGER, e,
"Konnte aktualisierte Metadaten nicht an den Server übermitteln");
return false;
}
if (changeListenerPermissions.isCurrentlyChanged()) {
if (!saveCustomPermissions()) {
return false;
}
}
changeMonitor.reset();
return true;
}
/**
* Helper to save the custom user permissions (those not included in
* ImageBaseWrite).
*
* @return true if successfully saved, false otherwise.
*/
private boolean saveCustomPermissions() {
try {
actionHandler.writeImagePermissions(image.getImageBaseId(),
ctlImagePermissionConfigurator.getPermissions());
LOGGER.info("Successfully saved new custom permissions");
} catch (TException e) {
ThriftError.showMessage(me, LOGGER, e,
"Konnte geänderte Berechtigungen nicht an den Server übermitteln");
return false;
}
return true;
}
/**
* Triggers the download of the given image version.
*
* @param selected image to download.
*/
private void performImageDownload(ImageVersionDetails selected) {
if (selected.getVersionId() == null) {
Gui.showMessageBox(this, "Ausgewählte Version ist ungültig", MessageType.ERROR, null, null);
return;
}
// using actionHandler here is not needed, as this ThriftAction works for downloads
// from either the master server or the satellite server
ThriftActions.initDownload(JOptionPane.getFrameForComponent(this), selected.versionId,
image.imageName, image.virtId, image.osId, selected.fileSize, null);
}
/**
* Triggers the deletion of the given image version.
*
* @param version image version to delete.
*/
private void deleteVersion(final ImageVersionDetails version) {
if (version == null)
return;
actionHandler.deleteImageVersion(version, new DeleteCallback() {
@Override
public void isDeleted(boolean success) {
refresh(success);
}
});
}
/**
* Triggers the deletion of a list of versions.
*
* @param versions to delete
*/
private void deleteVersions(List<ImageVersionDetails> versions) {
if (versions == null || versions.isEmpty())
return;
for (ImageVersionDetails version : versions) {
deleteVersion(version);
}
}
/**
* Extends the expiration date for given image versions to current date
* plus the user-supplied duration.
*
* @param versions to extend the validity of
*/
private void extendVersionExpiry(List<ImageVersionDetails> versions) {
int daysToExtend = -1;
if (versions.size() > 1) {
// more than one version given, ask the user once and use the value for all versions.
daysToExtend = ExpiryDateChooser.askFutureExpiryDuration(this, null);
if (daysToExtend == -1)
return;
}
int count = 0;
for (ImageVersionDetails img : versions) {
long currentExpiryTime = img.expireTime < Util.unixTime() ? Util.unixTime() : img.expireTime;
Date currentExpiryTimeAsDate = DateTimeHelper.endOfDay(new Date(currentExpiryTime * 1000l));
if (daysToExtend == -1) {
daysToExtend = ExpiryDateChooser.askFutureExpiryDuration(this, currentExpiryTimeAsDate);
if (daysToExtend == -1)
return;
}
currentExpiryTimeAsDate = DateTimeHelper.addDaysTo(currentExpiryTimeAsDate, daysToExtend);
try {
ThriftManager.getSatClient().setImageVersionExpiry(Session.getSatelliteToken(), img.versionId,
currentExpiryTimeAsDate.getTime() / 1000L);
count++;
} catch (TException e) {
ThriftError.showMessage(this, LOGGER, e,
"Konnte Ablaufdatum der Version " + img.versionId + " nicht verlängern.");
}
}
if (count > 0) {
Gui.showMessageBox(this, "Erfolgreich verlängerte Abbilder: " + count, MessageType.INFO, null,
null);
refresh(true);
}
}
/********************************************************************************
*
* General UI helpers
*
********************************************************************************/
/**
* @param forceRefresh
*/
private void refresh(boolean forceRefresh) {
String baseId = image.getImageBaseId();
synchronized (me) {
image = null;
}
setImage(baseId);
}
/**
* callback function when we received the image's details from the server
*/
private void fillDetails() {
if (image == null)
return;
txtTitle.setText(image.getImageName());
txtTitle.setCaretPosition(0);
txtDescription.setText(image.getDescription());
lblOwner.setUser(UserCache.find(image.getOwnerId()));
lblUpdater.setUser(UserCache.find(image.getUpdaterId()));
lblCreateTime.setText(FormatHelper.longDate(image.getCreateTime()));
lblUpdateTime.setText(FormatHelper.longDate(image.getUpdateTime()));
txtVersion.setText(image.getLatestVersionId());
txtId.setText(image.getImageBaseId());
chkIsTemplate.setSelected(image.isTemplate);
setTitle(image.getImageName());
// fill os combo, but only once :)
if (cboOperatingSystem.getItemCount() == 0) {
List<OperatingSystem> osList = MetaDataCache.getOperatingSystems();
// all fine, lets sort it
Collections.sort(osList, new Comparator<OperatingSystem>() {
public int compare(OperatingSystem o1, OperatingSystem o2) {
return o1.getOsName().compareTo(o2.getOsName());
}
});
for (OperatingSystem os : osList) {
cboOperatingSystem.addItem(os);
}
cboOperatingSystem.setSelectedItem(new OperatingSystem(image.getOsId(), null, null, null, 0, 0));
}
Virtualizer virt = MetaDataCache.getVirtualizerById(image.getVirtId(), true);
if (virt != null)
lblVirtualizer.setText(virt.getVirtName());
// fill share mode combo, if not already done
if (cboShareMode.getItemCount() == 0) {
for (ShareMode mode : ShareMode.values()) {
cboShareMode.addItem(mode);
}
}
cboShareMode.setSelectedItem(image.getShareMode());
String tagsString = "";
if (image.getTags() != null) {
for (String tag : image.getTags()) {
tagsString = tagsString + ", " + tag;
}
}
txtTags.setText(tagsString);
// init permissions, remember if the user had admin rights through default permissions
adminRightsFromDefaultPermissions = image.defaultPermissions.admin;
ctlImagePermissionConfigurator.initPanel(customPermissions, image.defaultPermissions, image.ownerId);
chkDefaultPermAdmin.setSelected(image.defaultPermissions.admin);
chkDefaultPermEdit.setSelected(image.defaultPermissions.edit);
chkDefaultPermDownload.setSelected(image.defaultPermissions.download);
chkDefaultPermLink.setSelected(image.defaultPermissions.link);
// Count the number of linked lectures to the image
int lectureCount = 0;
for (LectureSummary lecture : LectureCache.get(false)) {
if (lecture == null || lecture.imageBaseId == null)
continue;
if (lecture.imageBaseId.equals(image.imageBaseId))
lectureCount++;
}
lblLinkedLectureCount.setText(Integer.toString(lectureCount));
lblLinkedLectureCount.setForeground(lectureCount > 0 ? null : Color.RED);
btnShowLinkingLectures.setEnabled(lectureCount > 0);
// set the versions of the image to the table
tblVersions.setData(image.getVersions(), true);
// make fields editable is allowed
makeEditable(true);
changeMonitor.reset();
// finally do show it all
setVisible(true);
}
/**
* Enables/disables the editable fields based on 'editable'
*
* @param editable true to make fields editable, false otherwise.
*/
private void makeEditable(boolean editable) {
// always disable all buttons unless image's share mode is LOCAL or PUBLISH
if (image != null)
editable &= image.shareMode == ShareMode.LOCAL || image.shareMode == ShareMode.PUBLISH;
// now do the regular permission check
editable = editable && (ImagePerms.canEdit(image) || ImagePerms.canAdmin(image));
txtTitle.setEditable(editable);
txtDescription.setEditable(editable);
txtTags.setEditable(editable);
cboOperatingSystem.setEnabled(editable);
// cboShareMode.setEnabled(editable);
btnChangeOwner.setEnabled(editable && ImagePerms.canAdmin(image));
btnUpdateImage.setEnabled(editable);
if (actionHandler.isImagePublishSupported())
btnUploadToMaster.setEnabled(editable);
}
/**
* Opens a new ImageDetailsWindow showing the details of the image with ID =
* imageBaseId
*
* @param modalParent parent of this window
* @param imageBaseId id of the image to set the details of
*/
public static void open(Frame modalParent, String imageBaseId, ImageUpdatedCallback callback,
ImageDetailsActions actionHandler) {
ImageDetailsWindow win = new ImageDetailsWindow(modalParent, callback, actionHandler);
win.setImage(imageBaseId);
win.setVisible(true);
}
/* *******************************************************************************
*
* Dialog class overrides
*
* *******************************************************************************
*/
@SuppressWarnings("deprecation")
@Override
public void show() {
if (!isVisible()) {
pack();
MainWindow.centerShell(this);
}
super.show();
}
/* *******************************************************************************
*
* UIFeedback implementation
*
* *******************************************************************************
*/
@Override
public boolean wantConfirmQuit() {
return changeMonitor.isCurrentlyModified();
}
@Override
public void escapePressed() {
safeClose();
}
/*
* Safe close helper: checks if we have unsaved work and prompt the user for
* confirmation if so
*/
private boolean safeClose() {
if (changeMonitor.isCurrentlyModified()
&& !Gui.showMessageBox(me, "Änderungen werden verworfen, wollen Sie wirklich schließen?",
MessageType.QUESTION_YESNO, null, null))
return false;
dispose();
return true;
}
}