summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
blob: f46985ce17983856ed06684906b1c681282f5dd1 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                      
                      
                      

                                     

                                   
                               

                                   

                                    
                           

                             
                         
                      
                     
                           
 

                                  
                          
                             
                               


                                      
 
                               
                                    
                                                    
                                                      
                                                      

                                                         
                                                    
                                                     
                                               
                                              

                                                 
                                         
                                                 
                                               
                                                        
                                                
                                                                      
                                                                     
                                                       
                                                   
                                                 
                                                     
                                         
                                               
                                                              
                                                                 
                                             
                                                    

                                                     
                                            
                                         


                                              
                             
 


                                                             
                           
                                                                                        


                                                                                        


                         
                                                   
 
           

                                                                                  
           
                                                        
 


                                                                                


                                               
 


                            
                                                     
 


                                                      
                                              
 
           
                                                               
           
                                                                
 


                                                                     
                                                                        
 


                                                                      
                                                            
 


                           

                                                                                    
                                                                                
                                                                      

                                                                                      
 


                                                   



                                                         
                                                                                    
           

                                                                                   
                                   
                                         

                                                   







                                                                     


                                   
                                                                 
                                 
                                                                    
                                            

                         
                                                                       
                                 
                                                                    
                                              

                         


                                                                       
                                                                                  
                                              

                         





                                                                          







                                                                                                              
 



                                 


                                                                       
                                                                                 


                                                                                                     
                                                                                                                             
                                                                                                                                           
                                                                              
                                                                            
                                         
 
                                                                        

                         
 
                                                                       

                                                                       
                                                                                                                 



                                                                                                                           


                                                                                                          
                                                

                         
 
                                                                                             
 


                                                                     
                                                                          
                                                                    
                                                                                             

                                                     
                                                                          


                                                                                                                                                               
                                 
                                                                        
                                                                       
                                 

                                                                                       
                                 


                                                                        


                                                                                            
 

                         

                                               
                                             
                                   
                                           
                                                     


                                                             
 
                                    
                                                                                           
                                                                                         
                                                                               

                                                                     
                                                                
                                                                                       
                                 


                         


                                                      
                                                            

                                                                
                                                
                         
 

                                                                 
                                                
                         
 
                                                                 
                                                           
                                                                                         


                                                                                 
                                                                             





                                                                          
                                                                                                   


                                                                                          
                                                                                                                  
                                         
                                                                 
                                                                                                                



                                                                                                                                 

                                                                                                                               
                                                                                                

                                                                                                          

                                                                                               
                                 
 

                         

                                                 
 
                                    
                                                                                 
                                 
                                               






















                                                                               
 







                                                                
                                                                                      


                                                  
         
 

















                                                                                                                                                                     
                                                                                                                                       





                                         


                                                                                         
           
                                                                                          
           
                                                                                 
                                                                                    
                 
           
                                                                 
           
                                                        





                                                                                      
                                                                                    

                                                           
                                 
                                                          
                                                                      
                                 
 
                                                   
                                                             
                                                                        
 
                                 
                                              

                         
 
                                                                     

         
           




                                                                  
                                                                                 

                               

                                                                                                                      

                                    


           
                                                                                
                                                                
           
                                    



                                                                                             

                                                   



                                                        
         
 
           

                                                                            
           
                                       




                                                                                                                       
                                                

                                                                                                    

                                               



                                                    
                                                                                                                   
                                                                                                            


                                                                      
                                                                                                                         

                                                 
                                                                                                                                                                      





                                                                                                              


           


                                                                                  


                                                                          





                                                                                                                  
                                                                                  


                                                   
                                                
                                      






                                                                                                                               
                             
                                                                                           


                                                                                                                   
                                             
                         

                                                                       
                 

                                                                                                
                                         
                                                 
                                             
                                                                                 
                                                   

                            
         
 

                                             
                                                                                                       







                                                                                                             
           




                                                                         
                                                      
                                                                                                                      

                               

                                                                                                   
                                                                                                      
                                                                                                    

         





                                                                       
                                    
                               





                                                                                

         












                                                                         

















                                                                                                                              

        
 


                                                                                         
           

                                                                                          








                                                       
 
           

                                                                                 
                                    
                                  
                               





                                                                                                    

                                                                                         








                                                                                                                      

                                                               

                                                                         

                                                                                    
                                                               
                                                      
                                                            
                                               
 










                                                                                            
                         
                                                                                                                         
                 
 
                                                                                             

                                                                   
 






                                                                           
 
                                       



                                                                     

                                            
 


                                                                        

                                                                           


                                                                          

                                                                                         
                                                                    
 
                                                             



                                                                      


                                                  

                                 
 
           
                                                                              
                                                  
           








                                                                                                        


                                                   
                                                                  



                                                         
                                                                          



                                     
                                                                                                            





                                                                             
                                                                                                 


                                                                          
                 


                                                              





                                                                                                              
                                                                                                
 
                               
         
 
           




                                                                         




                                                                                                               




                                                                                                 
                                                     


                                                                                  

                                                               


           





                                                                                    

                                                                                                     
                                                                                                      
                                          
                                     
         
 
                                                                                          
           



                                                                                          








                                                     
 
                                                                                          
           



                                                                                          

                                          
                                                             



                                     

                            
 



                                                                                    
                                     
                                                           
                                                                                                                           
                                                                                        
                                     
                          
                            
         
 
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

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.helper.MessageType;
import org.openslx.dozmod.gui.helper.PopupMenu;
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.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.FormatHelper;
import org.openslx.dozmod.util.MapHelper;
import org.openslx.thrifthelper.ThriftManager;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
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;

	/**
	 * The original custom permissions as fetched from the server
	 */
	private Map<String, ImagePermissions> originalCustomPermissions;

	/**
	 * The original default permissions as fetched from the server
	 */
	private ImagePermissions originalDefaultPermissions;

	/**
	 * 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(
			"Ablaufzeitpunk vom aktuellen Datum ausgehend neu berechnen");

	private boolean metadataChanged = false;
	private boolean permissionsChanged = false;

	/**
	 * 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;

		// 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) {
				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);
			}
		});

		btnPermissions.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				// open the custom permission window and save returned default/custom permissions
				ImagePermissionWindow.open(me, customPermissions, image.defaultPermissions, image.ownerId);
				// since the window above gets references of the default/custom permission object
				// there is no need to further save the return value ...
				// THAT or we do work with copies in ImagePermissionWindow ...

				// for now let's stay with refs and just reactToChange() where we check if
				// the permissions stuff changed since the last call of fill()
				reactToChange();
			}
		});

		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);
		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;
						mnuNewLecture.setEnabled(!multiSelection && tblVersions.getSelectedItem().isValid
								&& ImagePerms.canLink(image));
						mnuDownload.setEnabled(!multiSelection && tblVersions.getSelectedItem().isValid
								&& ImagePerms.canDownload(image));
						mnuVmConfig.setEnabled(!multiSelection && tblVersions.getSelectedItem().isValid
								&& ImagePerms.canEdit(image));
						mnuDelete.setEnabled(ImagePerms.canEdit(image));
						mnuExtendExpiryDate.setEnabled(multiSelection
								|| tblVersions.getSelectedItem().isValid);
						pop.show(e.getComponent(), e.getX(), e.getY());
					}
				}

			}
		};
		scpVersions.addMouseListener(ma);
		tblVersions.addMouseListener(ma);

		// listen to changes
		final TextChangeListener docListener = new TextChangeListener() {
			@Override
			public void changed() {
				reactToChange();
			}
		};
		final ItemListener comboItemListener = new ItemListener() {
			@Override
			public void itemStateChanged(ItemEvent e) {
				if (e.getStateChange() == ItemEvent.SELECTED) {
					reactToChange();
				}
			}
		};
		final ActionListener checkBoxListener = new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				reactToChange();
			}
		};
		txtTitle.getDocument().addDocumentListener(docListener);
		txtDescription.getDocument().addDocumentListener(docListener);
		txtTags.getDocument().addDocumentListener(docListener);
		cboOperatingSystem.addItemListener(comboItemListener);
		cboShareMode.addItemListener(comboItemListener);
		chkIsTemplate.addActionListener(checkBoxListener);

		/**
		 * 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);
				}
				Gui.asyncExec(new Runnable() {
					@Override
					public void run() {
						if (machineDescription == null) {
							Gui.showMessageBox("Konnte VM-Konfiguration nicht abrufen.", MessageType.ERROR, LOGGER, null);
							return;
						}
						VirtConfigEditorWindow.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 "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);
		}
	}

	/**
	 * Called by the "Publish" button. Tries to upload that image to the
	 * masterserver.
	 */
	private void uploadToMaster() {
		if (metadataChanged || permissionsChanged) {
			if (Gui.showMessageBox("Sie haben unspeicherte Änderungen,  wollen Sie diese erst speichern?",
					MessageType.QUESTION_YESNO, LOGGER, null))
				saveChanges();
		}
		// let the user confirm or abort
		if (!Gui.showMessageBox("Wollen Sie diese VM wirklich landesweit veröffentlichen?",
				MessageType.QUESTION_YESNO, LOGGER, null))
			return;
		// start upload to masterserver
		QuickTimer.scheduleOnce(new Task() {
			@Override
			public void fire() {
				try {
					final String transferId = ThriftManager.getSatClient().publishImageVersion(
							Session.getSatelliteToken(), image.latestVersionId);
					Gui.asyncExec(new Runnable() {
						@Override
						public void run() {
							MainWindow.addPassiveTransfer(transferId, image.imageName, true);
						}
					});
					// TODO? Should we show a message? Transfer runs between master and sat, we just watch it. You could even close the client now
				} catch (TException e1) {
					ThriftError.showMessage(me, LOGGER, e1,
							"Upload der VM auf den Master-Server fehlgeschlagen");
				}
			}
		});
	}

	/**
	 * 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() {

		// We might only have admin perms because of the default permissions,
		// so we first write the permission map because we might remove our own default admin permissions.
		if (originalDefaultPermissions.admin && permissionsChanged) {
			if (!writeImagePermMap())
				return false;
			LOGGER.info("Successfully saved new default permissions");
			permissionsChanged = false;
		}

		// now trigger the actual action
		if (metadataChanged) {
			// 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);
			} catch (TException e) {
				ThriftError.showMessage(me, LOGGER, e,
						"Konnte aktualisierte Metadaten nicht an den Server übermitteln");
				return false;
			}
			LOGGER.info("Successfully saved new metadata");
			metadataChanged = false;
		}

		// if we haven't written the permission map yet and the permissions have changed
		if (permissionsChanged) {
			if (!writeImagePermMap())
				return false;
			LOGGER.info("Successfully saved new custom permissions");
			permissionsChanged = false;
		}
		return true;
	}

	private boolean writeImagePermMap() {
		try {
			actionHandler.writeImagePermissions(image.getImageBaseId(), customPermissions);
		} 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 list of versions to delete
	 */
	private void deleteVersions(List<ImageVersionDetails> versions) {
		if (versions == null || versions.isEmpty())
			return;
		for (ImageVersionDetails version : versions) {
			deleteVersion(version);
		}
	}

	private void extendVersionExpiry(List<ImageVersionDetails> versions) {
		int count = 0;
		for (ImageVersionDetails img : versions) {
			try {
				ThriftManager.getSatClient().setImageVersionExpiry(Session.getSatelliteToken(),
						img.versionId,
						Util.unixTime() + Session.getSatelliteConfig().maxImageValidityDays * 86400);
				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;
		// remember default permissions
		if (image.defaultPermissions != null) {
			originalDefaultPermissions = new ImagePermissions(image.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<String, ImagePermissions>();
			else
				originalCustomPermissions.clear();
			// fill it
			for (Entry<String, ImagePermissions> entry : customPermissions.entrySet()) {
				originalCustomPermissions.put(entry.getKey(), new ImagePermissions(entry.getValue()));
			}
		}
		txtTitle.setText(image.getImageName());
		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);

		// 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);
		mnuDelete.setEnabled(ImagePerms.canAdmin(image));
		mnuDownload.setEnabled(ImagePerms.canDownload(image));
		mnuNewLecture.setEnabled(ImagePerms.canAdmin(image));
		// make fields editable is allowed
		makeEditable(true);
		// finally do show it all
		setVisible(true);
	}

	/**
	 * Checks whether the user changed any fields of the image details and
	 * enables the save button if so TODO TAGS
	 */
	private void reactToChange() {
		metadataChanged = reactToChangeInternal();
		permissionsChanged = MapHelper.hasChanged(originalCustomPermissions, customPermissions);
		btnSaveChanges.setEnabled(metadataChanged || permissionsChanged);
	}

	private boolean reactToChangeInternal() {
		if (image == null)
			return false;
		boolean changed = false;
		// Image name
		if (txtTitle.getText().isEmpty()) {
			lblError.setText("Kein VM-Name gesetzt!");
			return false;
		}
		// Image description
		if (txtDescription.getText().isEmpty()) {
			lblError.setText("Keine Beschreibung angegeben!");
			return false;
		}

		// Operating system
		OperatingSystem newOs = cboOperatingSystem.getItemAt(cboOperatingSystem.getSelectedIndex());
		if (newOs == null) {
			lblError.setText("Kein Betriebssystem ausgewählt!");
			return false;
		}

		// Share mode
		ShareMode newShareMode = cboShareMode.getItemAt(cboShareMode.getSelectedIndex());
		if (newShareMode == null) {
			lblError.setText("Kein Share-Modus ausgewählt!");
			return false;
		}
		// mandatory checks done, remove error message
		lblError.setText(null);

		// Template, default permissions and custom permissions:
		// no sanity checks here only check if they changed
		changed = !txtTitle.getText().equals(image.getImageName())
				|| !txtDescription.getText().equals(image.getDescription())
				|| newOs.getOsId() != image.getOsId() || !newShareMode.equals(image.shareMode)
				|| chkIsTemplate.isSelected() != image.isTemplate
				|| !image.defaultPermissions.equals(originalDefaultPermissions);

		return changed;
	}

	/**
	 * 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);
		btnPermissions.setEnabled(editable && ImagePerms.canAdmin(image));
		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 metadataChanged || permissionsChanged;
	}

	@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 ((metadataChanged || permissionsChanged)
				&& !Gui.showMessageBox(me, "Änderungen werden verworfen, wollen Sie wirklich schließen?",
						MessageType.QUESTION_YESNO, null, null))
			return false;
		dispose();
		return true;
	}
}