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

                                      
                      

                                     

                                   

                                   

                                    

                             
                         
                      
                     
                           
 
                          
                             
                               

                                          
 
                               
                                    
                                                    
                                                      
                                                      

                                                         
                                                     
                                               
                                              

                                                 
                                         
                                                 
                                               
                                                
                                                                      
                                                                     
                                                       
                                                   
                                                         

                                                  
                                         
                                               
                                                              
                                                                 

                                                     
                                            
                                              
 


                                                             
                           
                                                                                        


                                                                                        


                         

                                                   


                                                                                


                                               
 


                            
                                                     
 


                                                      
                                              
 
           
                                                               
           
                                                                
 


                                                                     
                                                                        
 


                                                                      
                                                            
 


                           
                                                                             
                                                                        
                                                                      
 



                                                         
                                                                                    
           
                                                                                     
                                   
                                         







                                                                     


                                   
                                                                 
                                 
                                                                    
                                            

                         
                                                                       
                                 
                                                                    
                                              

                         


                                                                       
                                                                                  
                                              

                         


                                                                       
                                                                                 


                                                                                                     



                                                                                                                              
                                                                            
                                         
 
                                                                        

                         
                                                                       

                                                                       


                                                                                                                 


                                                                                                                                 


                                                                                                          
                                                

                         
 


                                                                     
                                                                          
                                                                    


                                                                                              
                                                                         


                                                                                                                                                               
                                 
                                                                              
                                                                       
                                 
                                                                            
                                                                
                                 
 

                         
                                              
                                                   
                                   
                                                 
 


                                                      
                                                            

                                                                
                                                
                         
 

                                                                 
                                                
                         
 
                                                                 
                                                                              
                                                                               
                                                                               
                                                                                   
                                                                 





                                                                                                                                         

                                                                                               

                                                                      


                                 

                                                            
 






                                                 
                                                                
                                    

                                                  





































                                                                               
         
 


                                                                                         
           
                                                                                          
           



                                                                                 
          
                                                                 
           
                                                        





                                                                                      
                                                                                    

                                                           
                                 
                                                          
                                                                      
                                 
 
                                                   
                                                             
                                                                        
 



                                       
                                                                                                               

         
           




                                                                  

                                                                                                              

                               

                                                                                                                      

                                    


           
                                                                   
           
                                    
                                                                     

                                                                                                                       


                                                                                                                      
                                                                                         


                                                                                                                      
                                                                                           
                             
                                                                                                               
                                                                                      
                                                
                                                                                                                     
                         
                 
                          
                                                                        
                                                 
                                   
                          
         
 
           




                                                                         
                                                      
                                                                                                                      

                               
                                                                                                      
                                                                                                    

         





                                                                       
                                    
                               






                                                                                                           

         


                                                                                         
           

                                                                                          








                                                       
 
           

                                                                                 
                             
                                  
                               















                                                                                                                                   

                                                               

                                                                         

                                                                                    
                                                               
                                                      
                                               
 










                                                                                            
                         
                                                                                                                         
                 
 
                                                                                             

                                                                   
 







                                                                           




                                                             
                                                            
 
                                                             
                                                                


                                                  

                                 
 
           
                                                                              
                                        
                    
           
                                         














                                                                                                  
                                                                                                            





                                                                             
                                                                                                 


                                                                          
                 







                                                                                                              

                                       
                                                   
                               
         
 
           
















                                                                                                 








                                                                                                       
                                     
         
 
                                                                                                












                                                                                          
 
                                                                                                



                                                                                          

                                          
                                                                     



                                     

                            
 




                                                                                    


                                                                                                                          

                               
         
 
package org.openslx.dozmod.gui.window;

import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.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.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

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.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.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.DefaultCustomPerms;
import org.openslx.dozmod.permissions.ImagePerms;
import org.openslx.dozmod.permissions.PermsHelper;
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.cache.MetaDataCache;
import org.openslx.dozmod.thrift.cache.UserCache;
import org.openslx.dozmod.util.FormatHelper;
import org.openslx.thrifthelper.ThriftManager;

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

	/**
	 * 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 JMenuItem popupItemNew = new JMenuItem("Neue Veranstaltung");
	private JMenuItem popupItemDownload = new JMenuItem("Download");
	private JMenuItem popupItemDelete = new JMenuItem("Löschen");

	/**
	 * 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) {
		super(modalParent);
		this.callback = callback;
		// 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);
			}
		});
		btnChangeOwner.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				UserListWindow.open(me, new UserAddedCallback() {
					@Override
					public void userAdded(UserInfo user, UserListWindow window) {
						window.dispose();
						if (Gui.showMessageBox(me,
								"Sind Sie sicher, dass sie die Besitzerrechte an "
										+ "einen anderen Account übertragen wollen?",
								MessageType.QUESTION_YESNO, LOGGER, null))
							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
				DefaultCustomPerms<ImagePermissions> combined = 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();
			}
		});

		/**
		 * Popup menu for the version table on the right side
		 */
		final PopupMenu pop = new PopupMenu(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ImageVersionDetails selected = versionTable.getSelectedItem();
				if (selected == null)
					return;
				if (e.getSource().equals(popupItemNew)) {
					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(popupItemDownload)) {
					performImageDownload(selected);
				}
				if (e.getSource().equals(popupItemDelete)) {
					deleteVersion(selected);
				}

			}
		});
		pop.addMenuItem(popupItemNew);
		pop.addMenuItem(popupItemDownload);
		pop.addSeparator();
		pop.addMenuItem(popupItemDelete);

		/**
		 * 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) {
				int r = versionTable.rowAtPoint(e.getPoint());
				if (r >= 0 && r < versionTable.getRowCount()) {
					// highlight the row and popup the menu
					versionTable.setRowSelectionInterval(r, r);
					if (e.isPopupTrigger()) {
						popupItemNew.setEnabled(
								versionTable.getSelectedItem().isValid && ImagePerms.canLink(image));
						popupItemDownload.setEnabled(
								versionTable.getSelectedItem().isValid && ImagePerms.canDownload(image));
						popupItemDelete.setEnabled(
								versionTable.getSelectedItem().isValid && ImagePerms.canAdmin(image));
						pop.show(e.getComponent(), e.getX(), e.getY());
					}
				} else {
					versionTable.clearSelection();
				}
			}
		};
		versionTableScrollPane.addMouseListener(ma);
		versionTable.addMouseListener(ma);

		/**
		 * Initial state of GUI elements
		 */
		setFocusable(true);
		btnSaveChanges.setEnabled(false);
		txtVersion.setEditable(false);
		txtId.setEditable(false);
		chkIsTemplate.setEnabled(Session.isSuperUser());
		makeEditable(false);
		// TODO finish ShareMode in server
		cboShareMode.setEnabled(false);

		// listen to changes
		final DocumentListener docListener = new DocumentListener() {
			@Override
			public void removeUpdate(DocumentEvent e) {
				changedUpdate(e);
			}

			@Override
			public void insertUpdate(DocumentEvent e) {
				changedUpdate(e);
			}

			@Override
			public void changedUpdate(DocumentEvent e) {
				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);
	}

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

				}
				fill();
			}
		};
		ThriftActions.getImageFullDetails(JOptionPane.getFrameForComponent(me), 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 (!ThriftActions.setImageOwner(JOptionPane.getFrameForComponent(me), image.getImageBaseId(),
				user)) {
			return;
		}
		Gui.showMessageBox(me, "Besitzrechte übertragen an " + FormatHelper.userName(user), MessageType.INFO,
				null, null);
		makeEditable(false);
		refresh(true);
	}

	/**
	 * Pushes the changes of the image details to the satellite
	 */
	private void saveChanges() {
		// 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()));
		// now trigger the actual action
		if (!ThriftActions.updateImageBase(JOptionPane.getFrameForComponent(me), image.getImageBaseId(), ibw))
			return;
		if (PermsHelper.hasChanged(originalCustomPermissions, customPermissions)) {
			try {
				ThriftManager.getSatClient().writeImagePermissions(Session.getSatelliteToken(),
						image.imageBaseId, customPermissions);
			} catch (TException e) {
				LOGGER.error("Fehler beim Übertragen der benutzerspezifischen Berechtigungen: ", e);
			}
		}
		// success
		LOGGER.info("Successfully saved changes to satellite.");
		btnSaveChanges.setEnabled(false);
		callback.updated();
		dispose();
	}

	/**
	 * 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;
		}
		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;
		ThriftActions.deleteImageVersion(JOptionPane.getFrameForComponent(this), version.versionId,
				new DeleteCallback() {
					@Override
					public void isDeleted(boolean success) {
						refresh(success);
					}
				});
	}

	/********************************************************************************
	 * 
	 * 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 fill() {
		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());
		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 = "";
		for (String tag : image.getTags()) {
			tagsString = tagsString + ", " + tag;
		}
		txtTags.setText(tagsString);
		chkIsTemplate.setSelected(image.isTemplate);

		// set the versions of the image to the table
		versionTable.setData(image.getVersions(), true);
		// 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 boolean reactToChange() {
		// disable save by default here, we will enable it at the end if all checks passed
		btnSaveChanges.setEnabled(false);
		boolean changed = false;
		// Image name
		if (txtTitle.getText().isEmpty()) {
			lblError.setText("Kein Imagename!");
			return false;
		}
		// Image description
		if (txtDescription.getText().isEmpty()) {
			lblError.setText("Keine Beschreibung!");
			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;
		}
		// 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)
				|| PermsHelper.hasChanged(originalCustomPermissions, customPermissions);

		lblError.setText(null);
		btnSaveChanges.setEnabled(changed);
		return changed;
	}

	/**
	 * Enables/disables the editable fields based on 'editable'
	 * 
	 * @param editable true to make fields editable, false otherwise.
	 */
	private void makeEditable(boolean editable) {
		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);
	}

	/**
	 * 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) {
		ImageDetailsWindow win = new ImageDetailsWindow(modalParent, callback);
		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 reactToChange() && btnSaveChanges.isEnabled();
	}

	@Override
	public void escapePressed() {
		safeClose();
	}

	/*
	 * Safe close helper: checks if we have unsaved work and prompt the user for
	 * confirmation if so
	 */
	private void safeClose() {
		if (reactToChange()
				&& !Gui.showMessageBox(me, "Änderungen werden verworfen, wollen Sie wirklich abbrechen?",
						MessageType.QUESTION_YESNO, LOGGER, null))
			return;
		dispose();
	}
}