summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
blob: 7809069d4629e9e6324d03bb52fecfa66254b5bf (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.*;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;
import org.openslx.bwlp.thrift.iface.*;
import org.openslx.dozmod.Branding;
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.PopupMenu;
import org.openslx.dozmod.gui.helper.*;
import org.openslx.dozmod.gui.panel.ContainerPanel;
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.Util;

/**
 * Window for displaying and editing the details of an image.
 */
public class ImageDetailsWindow extends ImageDetailsWindowLayout
		implements UiFeedback {

	/**
	 * Version for serialization.
	 */
	private static final long serialVersionUID = -1901954219828374015L;

	private static final Logger LOGGER = LogManager.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(I18n.WINDOW.getString("ImageDetails.MenuItem.newLecture.text"));
	private final JMenuItem mnuDownload = new JMenuItem(I18n.WINDOW.getString("ImageDetails.MenuItem.download.text"));
	private final JMenuItem mnuVmConfig = new JMenuItem(I18n.WINDOW.getString("ImageDetails.MenuItem.vmConfig.text"));
	private final JMenuItem mnuDelete = new JMenuItem(I18n.WINDOW.getString("ImageDetails.MenuItem.delete.text"));
	private final JMenuItem mnuExtendExpiryDate = new JMenuItem(I18n.WINDOW.getString("ImageDetails.MenuItem.extendExpirationDate.text"));

	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.debug("Valid: " + changeMonitor.isValid());
			}

			@Override public void modificationChanged() {
				btnSaveChanges.setEnabled(changeMonitor.isValid() && changeMonitor.wasEverModified());
				LOGGER.debug("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();
			}
		});
		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,
								I18n.WINDOW.getString("ImageDetails.Message.yesNo.changeOwner"),
								MessageType.QUESTION_YESNO, null, null))
							setImageOwner(user);
					}

				}, I18n.WINDOW.getString("ImageDetails.Button.changeOwner.caption"), 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() {
			/**
			 * Version for serialization.
			 */
			private static final long serialVersionUID = -8997886497303940355L;

			@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));
						// Allow configuration edition for downloaded VMs for now
						// Docker images can not be edited since configuration menu for containers does not exist
						mnuVmConfig.setEnabled(
								!multiSelection && selectedVersion.isValid && ImagePerms.canEdit(
										image ) && !TConst.VIRT_DOCKER.equals(image.getVirtId()));
						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(
				I18n.WINDOW.getString("ImageDetails.TextField.title.error")));
		changeMonitor.add(txtDescription).addConstraint(new TextNotEmptyConstraint(
				I18n.WINDOW.getString("ImageDetails.TextField.description.error")));
		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 I18n.WINDOW.getString("ImageDetails.ComboBox.OS.error");
					}
				});
		changeMonitor.addFixedCombo(cboShareMode, null)
				.addConstraint(new DialogChangeMonitor.ValidationConstraint<ShareMode>() {
					public String checkStateValid(ShareMode userInput) {
						if (userInput != null)
							return null;
						return I18n.WINDOW.getString("ImageDetails.ComboBox.shareMode.error");
					}
				});
		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(
									I18n.WINDOW.getString("ImageDetails.Message.error.couldNotRetrieveVMConfig"),
									MessageType.ERROR, LOGGER, null);
							return;
						}

						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,
				I18n.WINDOW.getString("ImageDetails.Message.info.setImageOwner", FormatHelper.userName(user)),
				MessageType.INFO, null, null);
		makeEditable(false);
		refresh();
	}

	/**
	 * 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(
					I18n.WINDOW.getString("ImageDetails.Message.error.publishNonVMWareImage",
							MetaDataCache.getVirtualizerById(image.virtId).virtName),
					MessageType.ERROR, null, null);
			return;
		}
		if (changeMonitor.isCurrentlyModified()) {
			if (Gui.showMessageBox(I18n.WINDOW.getString("ImageDetails.Message.yesNo.currentlyModified"),
					MessageType.QUESTION_YESNO, null, null)) {
				if (!saveChangesInternal()) {
					return;
				}
			}
		}
		// let the user confirm or abort
		if (!Gui.showMessageBox(I18n.WINDOW.getString("ImageDetails.Message.yesNo.confirmOrAbort"),
				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,
							I18n.WINDOW.getString("ImageDetails.Message.error.uploadFailed",
									DesktopEnvironment.Link.REGISTER_BWIDM.uri.toString()));
					return;
				}
				Gui.asyncExec(new Runnable() {
					@Override public void run() {
						MainWindow.addPassiveTransfer(transferId, image.imageName, true);
						// Inform user
						Gui.showMessageBox(ImageDetailsWindow.this,
								I18n.WINDOW.getString("ImageDetails.Message.info.passiveTransfer",
										Branding.getServiceName(), Branding.getApplicationName()),
								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,
					I18n.WINDOW.getString("ImageDetails.Message.error.saveChangesInternal"));
			return false;
		}

		if (changeListenerPermissions.isCurrentlyChanged()) {
			if (!saveCustomPermissions()) {
				return false;
			}
		}

		// TODO maybe there could be a nicer way to distinguish between image and containerImage
		if (image != null && image.getVirtId().equals(TConst.VIRT_DOCKER) ) {
			if(!pnlTabContainer.saveChanges(Session.getSatelliteToken(),image))
				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,
					I18n.WINDOW.getString("ImageDetails.Message.error.saveCustomPermissions"));
			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, I18n.WINDOW.getString("ImageDetails.Message.error.performImageDownload"),
					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();
			}
		});
	}

	/**
	 * 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 = Math.max(img.expireTime, Util.unixTime());
			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,
						I18n.WINDOW.getString("ImageDetails.Message.error.extendVersionExpiry", img.versionId));
			}
		}
		if (count > 0) {
			Gui.showMessageBox(this, I18n.WINDOW.getString("ImageDetails.Message.info.extendVersionExpiry", count),
					MessageType.INFO, null, null);
			refresh();
		}
	}

	/********************************************************************************
	 *
	 * General UI helpers
	 *
	 ********************************************************************************/

	/**
	 *
	 */
	private void refresh() {
		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);


		// If this Image is from type Docker (Container) show the new Container Tab
		if (image != null && image.getVirtId().equals(TConst.VIRT_DOCKER)) {
			lblVirtualizer.setText(TConst.VIRT_DOCKER);
			pnlTabContainer.init(Session.getSatelliteToken(), image, ContainerPanel.IMAGE_CONTEXT);
			pnlTabContainer.addToChangeMonitor(changeMonitor);
			showContainerTab();

			// TODO Currently, do not allow user to upload a new version or share an Container Image.
			btnUploadToMaster.setEnabled(false);
		}
	}

	/**
	 * 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
	 *
	 * *******************************************************************************
	 */
	@Override
	public void setVisible(boolean visible) {
		if (!isVisible()) {
			pack();
			MainWindow.centerShell(this);
		}

		super.setVisible(visible);
	}

	/* *******************************************************************************
	 *
	 * 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, I18n.WINDOW.getString("ImageDetails.Message.yesNo.safeClose"),
						MessageType.QUESTION_YESNO, null, null))
			return false;
		dispose();
		return true;
	}
}