Java tutorial
// Copyright 2007 Hitachi Data Systems // All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package com.archivas.clienttools.arcmover.gui; import com.archivas.clienttools.arcmover.gui.namespacewizard.NamespaceProfileMgrDialog; import com.archivas.clienttools.arcmover.gui.panels.ProfilePanel; import com.archivas.clienttools.arcmover.gui.settings.PreferencesDialog; import com.archivas.clienttools.arcmover.gui.ssl.SSLCertificateAllowDialog; import com.archivas.clienttools.arcmover.gui.util.DialogDimensionProperties; import com.archivas.clienttools.arcmover.gui.util.FixedWidthPanel; import com.archivas.clienttools.arcmover.gui.util.GUIHelper; import com.archivas.clienttools.arcmover.gui.util.SelfDestructiveDialog; import com.archivas.clienttools.arcutils.api.jobs.CopyJob; import com.archivas.clienttools.arcutils.api.jobs.DeleteJob; import com.archivas.clienttools.arcutils.api.jobs.JobSpec; import com.archivas.clienttools.arcutils.api.jobs.ManagedJob; import com.archivas.clienttools.arcutils.api.jobs.SetMetadataJob; import com.archivas.clienttools.arcutils.config.ConfigurationException; import com.archivas.clienttools.arcutils.config.ConfigurationHelper; import com.archivas.clienttools.arcutils.config.HCPMoverProperties; import com.archivas.clienttools.arcutils.impl.adapter.StorageAdapterException; import com.archivas.clienttools.arcutils.profile.AbstractProfileBase; import com.archivas.clienttools.arcutils.profile.FileSystemProfile; import com.archivas.clienttools.arcutils.profile.HCAPProfile; import com.archivas.clienttools.arcutils.profile.ProfileManager; import com.archivas.clienttools.arcutils.model.*; import com.archivas.clienttools.arcutils.utils.FileListParser; import com.archivas.clienttools.arcutils.utils.FileUtil; import com.archivas.clienttools.arcutils.utils.UidGidUtil; import com.archivas.clienttools.arcutils.utils.database.DBUtils; import com.archivas.clienttools.arcutils.utils.database.DatabaseException; import com.archivas.clienttools.arcutils.utils.database.DatabaseResourceManager; import com.archivas.clienttools.arcutils.utils.database.NonFatalDatabaseException; import com.archivas.clienttools.arcutils.utils.net.SSLCertChain; import com.archivas.clienttools.arcutils.utils.net.SSLCertificateCallback; import com.jgoodies.looks.plastic.PlasticLookAndFeel; import com.jgoodies.looks.plastic.PlasticXPLookAndFeel; import com.jgoodies.looks.plastic.theme.ExperienceBlue; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; public class HCPDataMigrator extends JFrame { private static final String CLASS_FULL_NAME = HCPDataMigrator.class.getName(); private static final Logger LOG = Logger.getLogger(CLASS_FULL_NAME); // logging public static final String NEWLINE = System.getProperty("line.separator"); public static final String PRODUCT_NAME = "Open Data Migrator for Hitachi Content Platform"; // last selected profiles private static final String LEFT_PROFILE_NAME = "hcpdm.profile.left.name"; private static final String RIGHT_PROFILE_NAME = "hcpdm.profile.right.name"; private static final String FILE_CHOOSER_LOOK_IN_LABEL_TEXT_PROPERTY = "FileChooser.lookInLabelText"; private static final String FILE_CHOOSER_FILE_NAME_LABEL_TEXT_PROPERTY = "FileChooser.fileNameLabelText"; private static final String FILE_CHOOSER_FILES_OF_TYPE_LABEL_TEXT_PROPERTY = "FileChooser.filesOfTypeLabelText"; // Copyright year for splash screen/about public static final int COPYRIGHT_YEAR = 2007; // GUI Support SplashDialog splashDialog; public static ImageIcon appImageIcon; private DialogDimensionProperties dialogProperties = new DialogDimensionProperties(CLASS_FULL_NAME, 700, 550); public static Cursor waitCursor = new Cursor(Cursor.WAIT_CURSOR); public static Cursor normalCursor = null; // GUI private static HCPDataMigrator mainFrame; private ProfilePanel leftProfilePanel; private ProfilePanel rightProfilePanel; protected JButton putButton; protected JButton getButton; protected JMenuItem openMenuItem = null; protected JMenuItem deleteMenuItem = null; protected JMenuItem setMetadataMenuItem = null; protected JMenuItem renameMenuItem = null; protected JMenuItem propertiesMenuItem = null; private JMenuItem toolbarMenuItem = null; private JToolBar toolBar; private JComboBox fontChooserCB; private JComboBox fontSizeCB; private static final Integer[] FONT_SIZES = { 8, 9, 10, 11, 12, 14 }; private List<JMenuItem> lockableMenuItems = null; public static HCPDataMigrator getInstance() { return mainFrame; } public HCPDataMigrator(SplashDialog splash) throws StorageAdapterException { mainFrame = this; // Initialize the Splash Screen LOG.fine("Initializing Splash Screen"); // set up icons first so that we can associate the app icon with the splash screen initializeIcons(); splashDialog = splash; setTitle(PRODUCT_NAME); // Initialize Application LOG.fine("Initializing Application"); // Initialize the GUI LOG.fine("Initializing GUI"); ProfileManager.initialize(new SSLCertificateCallback() { public void validCertCallback(AbstractProfileBase profile, SSLCertChain certChain) { profile.setSSLCertChain(certChain); LOG.log(Level.FINE, "validCertCallback for profile " + profile + ": " + certChain); } public AllowSSLCert exceptionCallback(AbstractProfileBase profile, SSLCertChain certChain, String warningString) { profile.setSSLCertChain(certChain); SSLCertificateAllowDialog sslCertificateAllowDialog = new SSLCertificateAllowDialog(profile); sslCertificateAllowDialog.setWarningText(warningString); sslCertificateAllowDialog.setTitle("Allow Security Exception"); // center the dialog on the main window and display GUIHelper.centerDialog(HCPDataMigrator.getInstance(), sslCertificateAllowDialog); sslCertificateAllowDialog.setVisible(true); return sslCertificateAllowDialog.getAllowCert(); } }); layoutGuiComponents(); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); setSize(new Dimension(dialogProperties.width, dialogProperties.height)); setLocationRelativeTo(null); // center on screen initializeMenuBar(); initializeWindowListeners(); initializeButtons(); GUIHelper.invokeAndWait(new Runnable() { public void run() { selectionFromPanel(null); } }, "clear selection during initialization"); LOG.fine("Initialization complete"); this.setMinimumSize(new Dimension(650, 500)); setCursor(waitCursor); setVisible(true); splashDialog.cleanUp(); setCursor(normalCursor); loadProfilePanels(); } private void layoutGuiComponents() { // // Buttons (left and right arrows) // getButton = new JButton(); getButton.setIcon(new ImageIcon(getClass().getResource("/images/Rewind24.gif"))); getButton.setText(""); getButton.setToolTipText("Copy selected files from right to left."); putButton = new JButton(); putButton.setIcon(new ImageIcon(getClass().getResource("/images/FastForward24.gif"))); putButton.setText(""); putButton.setToolTipText("Copy selected files from left to right."); JPanel moveButtonsPanel = new FixedWidthPanel(); moveButtonsPanel.setLayout(new BoxLayout(moveButtonsPanel, BoxLayout.Y_AXIS)); moveButtonsPanel.add(Box.createVerticalGlue()); moveButtonsPanel.add(putButton); moveButtonsPanel.add(Box.createVerticalStrut(25)); moveButtonsPanel.add(getButton); moveButtonsPanel.add(Box.createVerticalGlue()); JPanel p = new JPanel(); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); p.setBorder(new EmptyBorder(12, 12, 12, 12)); leftProfilePanel = new ProfilePanel(); p.add(leftProfilePanel); p.add(Box.createHorizontalStrut(25)); p.add(moveButtonsPanel); p.add(Box.createHorizontalStrut(25)); rightProfilePanel = new ProfilePanel(); p.add(rightProfilePanel); // Create the main panel that has the toolbar at start and everything else in the center initializeToolBar(); JPanel mainPanel = new JPanel(new BorderLayout()); mainPanel.add(toolBar, BorderLayout.NORTH); mainPanel.add(p, BorderLayout.CENTER); getContentPane().add(mainPanel); } private void initializeToolBar() { // determine all supported font families and add to combo box GraphicsEnvironment e = GraphicsEnvironment.getLocalGraphicsEnvironment(); String[] allFonts = e.getAvailableFontFamilyNames(); fontChooserCB = new JComboBox(allFonts); fontSizeCB = new JComboBox(FONT_SIZES); ActionListener l = new ActionListener() { public void actionPerformed(ActionEvent e) { setFont(); } }; fontChooserCB.addActionListener(l); fontSizeCB.addActionListener(l); // lay out the toolbar GUI components toolBar = new JToolBar(PRODUCT_NAME + " File List Font"); toolBar.add(new JLabel("Font:")); toolBar.addSeparator(); toolBar.add(fontChooserCB); fontChooserCB.setMaximumSize(fontChooserCB.getPreferredSize()); toolBar.addSeparator(); toolBar.add(fontSizeCB); fontSizeCB.setMaximumSize(fontSizeCB.getPreferredSize()); toolBar.addSeparator(); // Set toolbar to visible or not depending on last value toolBar.setVisible(HCPMoverProperties.TOOLBAR_VISIBLE.getAsBoolean()); // set initial selection of font family and size to default font used Font initialFont = leftProfilePanel.getFileFont(); // Now try to read in the user's preference try { String fontFamily = HCPMoverProperties.FONT_FAMILY.get(); int fontSize = HCPMoverProperties.FONT_SIZE.getAsInt(); fontSize = Math.max(fontSize, 8); // at least size 8 fontSize = Math.min(fontSize, 14); // at most size 14 // According to the API, if the fontFamily doesn't exist, then "Dialog" is used, i.e. // initialFont.getFamily() will return "Dialog" initialFont = new Font(fontFamily, Font.PLAIN, fontSize); } catch (Exception ignore) { // do nothing; we'll use the font that the L&F uses by default for profile panel from // above } fontChooserCB.setSelectedItem(initialFont.getFamily()); fontSizeCB.setSelectedItem(initialFont.getSize()); // Now tell profile panels to use the correct initial font setFont(); } private void setFont() { String newFontName = (String) fontChooserCB.getSelectedItem(); Integer newFontSize = (Integer) fontSizeCB.getSelectedItem(); if (newFontName != null && newFontSize != null) { Font fileFont = new Font(newFontName, Font.PLAIN, newFontSize); HCPMoverProperties.FONT_FAMILY.set(fileFont.getFamily()); HCPMoverProperties.FONT_SIZE.set(fileFont.getSize()); leftProfilePanel.setFileFont(fileFont); rightProfilePanel.setFileFont(fileFont); JobDialog.setFileFont(fileFont); } } private void initializeIcons() { URL appImageIconURL = HCPDataMigrator.class.getResource("/images/DataMigratorIcon16x16.png"); appImageIcon = new ImageIcon(appImageIconURL); setIconImage(appImageIcon.getImage()); } private void initializeButtons() { putButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { copyLeftToRight(); } catch (Exception ex) { String msg = DBUtils.getErrorMessage("An error occurred copying files", ex); GUIHelper.showMessageDialog(HCPDataMigrator.this, msg, "Error Copying Files", JOptionPane.ERROR_MESSAGE); LOG.log(Level.WARNING, msg, ex); } } }); getButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { copyRightToLeft(); } catch (Exception ex) { String msg = DBUtils.getErrorMessage("An error occurred copying files", ex); GUIHelper.showMessageDialog(HCPDataMigrator.this, msg, "Error Copying Files", JOptionPane.ERROR_MESSAGE); LOG.log(Level.WARNING, msg, ex); } } }); } private void initializeMenuBar() throws StorageAdapterException { JMenuBar menuBar; JMenu menu; JMenuItem menuItem; // create menu bar menuBar = new JMenuBar(); // create File menu menu = new JMenu("File"); menu.setMnemonic(KeyEvent.VK_F); menu.getAccessibleContext().setAccessibleDescription("File menu"); menuBar.add(menu); // Form list of lockable items lockableMenuItems = new ArrayList<JMenuItem>(); // create File menu items menuItem = new JMenuItem("Saved Jobs", KeyEvent.VK_S); menuItem.getAccessibleContext().setAccessibleDescription("Manage saved jobs"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { savedJobsMenuItemAction(); } catch (Exception ex) { String errMsg = DBUtils.getErrorMessage("An error occurred getting the list of saved jobs", ex); LOG.log(Level.SEVERE, errMsg, ex); GUIHelper.showMessageDialog(HCPDataMigrator.this, errMsg, "Error Reading Jobs", JOptionPane.ERROR_MESSAGE); } } }); menu.add(menuItem); lockableMenuItems.add(menuItem); // create File menu items menuItem = new JMenuItem("Import Copy Job from File", KeyEvent.VK_C); menuItem.getAccessibleContext().setAccessibleDescription("Load a Copy Job File"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loadCopyJobMenuItemAction(); } }); menu.add(menuItem); lockableMenuItems.add(menuItem); menuItem = new JMenuItem("Import Delete Job from File", KeyEvent.VK_I); menuItem.getAccessibleContext().setAccessibleDescription("Load a Delete Job File"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loadDeleteJobMenuItemAction(); } }); menu.add(menuItem); lockableMenuItems.add(menuItem); menuItem = new JMenuItem("Import Metadata Job from File", KeyEvent.VK_M); menuItem.getAccessibleContext().setAccessibleDescription("Load a Metadata Job File"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loadMetadataJobMenuItemAction(); } }); menu.add(menuItem); lockableMenuItems.add(menuItem); menu.addSeparator(); menuItem = new JMenuItem("Namespace Profile Manager", KeyEvent.VK_N); menuItem.getAccessibleContext().setAccessibleDescription("Open the Namespace Profile Manager"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { loadProfileManagerMenuItemAction(); } }); menu.add(menuItem); lockableMenuItems.add(menuItem); menu.addSeparator(); openMenuItem = new JMenuItem("Open", KeyEvent.VK_O); openMenuItem.setEnabled(false); openMenuItem.getAccessibleContext().setAccessibleDescription("Open Object"); openMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { openObjectAction(); } }); menu.add(openMenuItem); deleteMenuItem = new JMenuItem("Delete", KeyEvent.VK_D); deleteMenuItem.setEnabled(false); deleteMenuItem.getAccessibleContext().setAccessibleDescription("Delete Object"); deleteMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { deleteObjectAction(); } }); menu.add(deleteMenuItem); setMetadataMenuItem = new JMenuItem("Set Metadata" /* * , KeyEvent.VK_E // no available * reasonable letter */); setMetadataMenuItem.setEnabled(false); setMetadataMenuItem.getAccessibleContext().setAccessibleDescription("Set Metadata"); setMetadataMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { setMetadataObjectAction(); } }); menu.add(setMetadataMenuItem); renameMenuItem = new JMenuItem("Rename", KeyEvent.VK_R); renameMenuItem.setEnabled(false); renameMenuItem.getAccessibleContext().setAccessibleDescription("Rename Object"); renameMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { renameObjectAction(); } }); menu.add(renameMenuItem); propertiesMenuItem = new JMenuItem("Properties", KeyEvent.VK_P); propertiesMenuItem.setMnemonic(KeyEvent.VK_P); propertiesMenuItem.setEnabled(false); propertiesMenuItem.getAccessibleContext().setAccessibleDescription("Object Properties"); propertiesMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { objectPropertiesAction(); } }); menu.add(propertiesMenuItem); menu.addSeparator(); menuItem = new JMenuItem("Exit", KeyEvent.VK_X); menuItem.setMnemonic(KeyEvent.VK_X); menuItem.getAccessibleContext().setAccessibleDescription("Exit this application"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { quit(); } }); menu.add(menuItem); // create Edit menu menu = new JMenu("Edit"); menu.setMnemonic(KeyEvent.VK_E); menu.getAccessibleContext().setAccessibleDescription("Edit menu"); menuBar.add(menu); // create Edit menu items menuItem = new JMenuItem("Preferences", KeyEvent.VK_P); menuItem.getAccessibleContext().setAccessibleDescription("Application preferences"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { preferencesMenuItemAction(); } }); menu.add(menuItem); // create View menu menu = new JMenu("View"); menu.setMnemonic(KeyEvent.VK_V); menu.getAccessibleContext().setAccessibleDescription("View menu"); menuBar.add(menu); // create View menu items menuItem = new JMenuItem("Refresh"); menuItem.setMnemonic(KeyEvent.VK_R); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0)); menuItem.getAccessibleContext().setAccessibleDescription("Refresh view"); menuItem.setIcon(GUIHelper.REFRESH_ICON); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { refreshPanels(); JobDialog.showJob(); } }); menu.add(menuItem); toolbarMenuItem = new JCheckBoxMenuItem("Font Toolbar"); toolbarMenuItem.getAccessibleContext().setAccessibleDescription("Display or Hide the Font Toolbar"); toolbarMenuItem.setMnemonic(KeyEvent.VK_T); toolbarMenuItem.setSelected(HCPMoverProperties.TOOLBAR_VISIBLE.getAsBoolean()); toolbarMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { toolBar.setVisible(toolbarMenuItem.isSelected()); HCPMoverProperties.TOOLBAR_VISIBLE.set(toolbarMenuItem.isSelected()); } }); menu.add(toolbarMenuItem); // create Help menu menu = new JMenu("Help"); menu.setMnemonic(KeyEvent.VK_H); menu.getAccessibleContext().setAccessibleDescription("Help menu"); menuBar.add(menu); // create Help menu items menuItem = new JMenuItem("About", KeyEvent.VK_A); menuItem.getAccessibleContext().setAccessibleDescription("About this application"); menuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { aboutMenuItemAction(); } }); menu.add(menuItem); // add menu bar to window setJMenuBar(menuBar); } private void quit() { // Veto with error message if JobDialog is open if (JobDialog.isOpen()) { LOG.log(Level.INFO, "Trying to close with open Job Dialog."); showMigrator(true); JOptionPane.showMessageDialog(HCPDataMigrator.this, "The current job must be closed before closing the application.", "Error Closing Application", JOptionPane.ERROR_MESSAGE); SwingUtilities.invokeLater(new Runnable() { public void run() { JobDialog.showJob(); } }); } else { // remember size Dimension dimension = getSize(); dialogProperties.width = dimension.width; dialogProperties.height = dimension.height; dialogProperties.persist(); HCPMoverProperties.persist(); try { ProfileManager.saveProfiles(); } catch (ConfigurationException f) { LOG.log(Level.WARNING, "Failed to save profiles on exit.", f); } shutdown(); } } private void initializeWindowListeners() { // add a hook to persist window dimensions on close addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { quit(); } public void windowDeiconified(WindowEvent e) { toFront(); requestFocus(); } }); addComponentListener(new ComponentAdapter() { public void componentResized(ComponentEvent evt) { if (leftProfilePanel != null) { leftProfilePanel.resizeFileList(); } if (rightProfilePanel != null) { rightProfilePanel.resizeFileList(); } } }); PropertyChangeListener listener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if (!SwingUtilities.isEventDispatchThread()) { String errMsg = "propertyChange is not on the EDT but it should be"; IllegalStateException ex = new IllegalStateException(errMsg); LOG.log(Level.SEVERE, errMsg, ex); throw ex; } updateLockable(); } }; leftProfilePanel.addPropertyChangeListener(ProfilePanel.LOCK_PROPERTY, listener); rightProfilePanel.addPropertyChangeListener(ProfilePanel.LOCK_PROPERTY, listener); } public void updateLockable() { updateButtons(); updateFileMenu(); } public void refreshProfilePanel(AbstractProfileBase profile) { try { setCursor(waitCursor); if (leftProfilePanel.getSelectedProfile() == profile) { leftProfilePanel.refreshPathAndFileList(); } if (rightProfilePanel.getSelectedProfile() == profile) { rightProfilePanel.refreshPathAndFileList(); } } finally { setCursor(normalCursor); } } public void refreshProfiles() { try { setCursor(waitCursor); leftProfilePanel.refreshProfiles(); rightProfilePanel.refreshProfiles(); } finally { setCursor(normalCursor); repaint(); // repaint, otherwise the profile drop down doesn't display the selected // profile } } private void loadProfilePanels() { try { setCursor(waitCursor); AbstractProfileBase profile = null; String profileName = ConfigurationHelper.getStringProperty(LEFT_PROFILE_NAME, null); if (profileName != null && ProfileManager.doesProfileNameExist(profileName)) { profile = ProfileManager.getProfileByName(profileName); } if (profile == null) { profile = FileSystemProfile.LOCAL_FILESYSTEM_PROFILE; } final AbstractProfileBase leftProfile = profile; GUIHelper.invokeAndWait(new Runnable() { public void run() { leftProfilePanel.setSelectedProfile(leftProfile); } }, "set left profile"); profile = null; profileName = ConfigurationHelper.getStringProperty(RIGHT_PROFILE_NAME, null); if (profileName != null && ProfileManager.doesProfileNameExist(profileName)) { profile = ProfileManager.getProfileByName(profileName); } if (profile == null) { profile = FileSystemProfile.LOCAL_FILESYSTEM_PROFILE; } final AbstractProfileBase rightProfile = profile; GUIHelper.invokeAndWait(new Runnable() { public void run() { rightProfilePanel.setSelectedProfile(rightProfile); } }, "set right profile"); } finally { setCursor(normalCursor); repaint(); // repaint, otherwise the profile drop down doesn't display the selected // profile } } public void loadCopyJobMenuItemAction() { startImportJob(new ImportCopyJobDialog()); } public void loadDeleteJobMenuItemAction() { startImportJob(new ImportDeleteJobDialog()); } public void loadMetadataJobMenuItemAction() { startImportJob(new ImportMetadataJobDialog()); } public void startImportJob(ImportJobDialog importDialog) { // setVisible(true) won't return until the dialog is closed importDialog.setVisible(true); if (importDialog.okClicked()) { String file = importDialog.getImportFilePath(); AbstractProfileBase sourceProfile = importDialog.getSourceProfile(); String sourcePath = sourceProfile.encode(importDialog.getSourcePath()); AbstractProfileBase targetProfile = null; String targetPath = ""; ManagedJob.Type jobType = importDialog.getJobType(); if (jobType.hasTarget()) { targetProfile = importDialog.getTargetProfile(); targetPath = targetProfile.encode(importDialog.getTargetPath()); } this.getGlassPane().setCursor(waitCursor); this.getGlassPane().setVisible(true); // Create a job File inputFile = new File(file); ManagedJob job; switch (jobType) { case DELETE: job = new DeleteJob(sourceProfile, inputFile); break; case SET_METADATA: job = new SetMetadataJob(sourceProfile, inputFile); break; case COPY: job = new CopyJob(sourceProfile, targetProfile, inputFile); job.setTargetPath(targetPath); break; default: throw new IllegalArgumentException(jobType.toString()); } job.setSourcePath(sourcePath); LoadSchedule schedule = LoadSchedule.getDefaultLoadSchedule(); job.setLoadSchedule(schedule); try { // Validate the file FileListParser.validateFile(inputFile, sourceProfile, sourcePath, targetPath); } catch (Exception e) { String msg = DBUtils.getErrorMessage("An error occurred parsing file " + file, e); LOG.log(Level.WARNING, msg, e); GUIHelper.showMessageDialog(this, msg, "Error Reading Input File", JOptionPane.ERROR_MESSAGE); job = null; } this.getGlassPane().setCursor(null); this.getGlassPane().setVisible(false); try { if (job != null) { JobDialog.openNewJob(job); } } catch (Exception e) { String msg = DBUtils.getErrorMessage("An error occurred loading a new job", e); LOG.log(Level.WARNING, msg, e); GUIHelper.showMessageDialog(this, msg, "Error Loading Job", JOptionPane.ERROR_MESSAGE); } HCPMoverProperties.IMPORT_JOB_LAST_DIRECTORY.set(file); } } private void savedJobsMenuItemAction() throws DatabaseException { SavedJobsDialog.openSavedJobsDialog(); } private void loadProfileManagerMenuItemAction() { new NamespaceProfileMgrDialog().setVisible(true); } private void aboutMenuItemAction() { new AboutDialog(this, "3.0.14.12345"); } private void preferencesMenuItemAction() { PreferencesDialog d = new PreferencesDialog(); d.setLocationRelativeTo(this); d.setVisible(true); } private JobSpec getCurrentJob(ProfilePanel sourcePanel, ProfilePanel targetPanel) throws DatabaseException { AbstractProfileBase sourceProfile = sourcePanel.getSelectedProfile(); AbstractProfileBase targetProfile = targetPanel.getSelectedProfile(); ArcMoverFile[] selectedFiles = sourcePanel.getSelectedFiles(); List<ArcCopyFile> fileNameList = new ArrayList<ArcCopyFile>(); String targetPath = targetPanel.getCurrentDirectory().getPath(); // add each selected file to the list for (ArcMoverFile nextFile : selectedFiles) { String targetFilename = nextFile.getFileName(); // // encode/decode the target filename as necessary // if (sourceProfile.usesEncodedPaths() && !targetProfile.usesEncodedPaths()) { targetFilename = sourceProfile.decode(targetFilename); } else if (!sourceProfile.usesEncodedPaths() && targetProfile.usesEncodedPaths()) { targetFilename = targetProfile.encode(targetFilename); } ArcCopyFile nextCopyFile = new ArcCopyFile(nextFile, targetPanel.getSelectedProfile(), FileUtil .resolvePath(targetPath, targetFilename, targetPanel.getSelectedProfile().getPathSeparator())); fileNameList.add(nextCopyFile); } CopyJob job = new CopyJob(sourcePanel.getSelectedProfile(), targetPanel.getSelectedProfile(), fileNameList); job.setSourcePath(sourcePanel.getCurrentDirectory().getPath()); job.setTargetPath(targetPath); return job; } public CopyJob configureJob(CopyJob job) throws DatabaseException { // The following copies the values from our preferences. We do not use this in the // case where the source is HCP. Filtering that case out here if (!(job.getSourceProfile() instanceof HCAPProfile)) { if (HCPMoverProperties.PERMISSIONS_UID.get().length() > 0) { try { job.setUid(UidGidUtil.validateId(HCPMoverProperties.PERMISSIONS_UID.get())); } catch (NumberFormatException exception) { LOG.warning("Ignoring invalid UID value: " + HCPMoverProperties.PERMISSIONS_UID.get()); } } if (HCPMoverProperties.PERMISSIONS_GID.get().length() > 0) { try { job.setGid(UidGidUtil.validateId(HCPMoverProperties.PERMISSIONS_GID.get())); } catch (NumberFormatException exception) { LOG.warning("Ignoring invalid GID value: " + HCPMoverProperties.PERMISSIONS_GID.get()); } } if (HCPMoverProperties.PERMISSIONS_FILE_MODE.get().length() > 0) { try { if (HCPMoverProperties.PERMISSIONS_FILE_MODE.getAsInt() >= 0) job.setFilePermissions(HCPMoverProperties.PERMISSIONS_FILE_MODE.getAsInt()); } catch (NumberFormatException exception) { LOG.warning( "Ignoring invalid file mode value: " + HCPMoverProperties.PERMISSIONS_FILE_MODE.get()); } } if (HCPMoverProperties.PERMISSIONS_DIR_MODE.get().length() > 0) { try { if (HCPMoverProperties.PERMISSIONS_DIR_MODE.getAsInt() >= 0) job.setDirPermissions(HCPMoverProperties.PERMISSIONS_DIR_MODE.getAsInt()); } catch (NumberFormatException exception) { LOG.warning( "Ignoring invalid dir mode value: " + HCPMoverProperties.PERMISSIONS_DIR_MODE.get()); } } job.setIndex(HCPMoverProperties.INDEX_MODE.getAsTriState().toBoolean()); job.setShred(HCPMoverProperties.SHRED_MODE.getAsTriState().toBoolean()); job.setRetentionHold(HCPMoverProperties.RETENTION_HOLD_MODE.getAsTriState().toBoolean()); // check if an explicit retention period is being provided job.setRetention(Retention.fromProperties( Retention.Type.fromUIName(HCPMoverProperties.RETENTION_TYPE.get()), HCPMoverProperties.RETENTION_USER_INPUT.get(), HCPMoverProperties.RETENTION_HCAP_VALUE.get())); if (HCPMoverProperties.OWNER.get().length() > 0) { job.setOwner(Owner.createFromStringRepresentation(HCPMoverProperties.OWNER.get())); } } return job; } private void copyLeftToRight() throws DatabaseException { copyFiles(leftProfilePanel, rightProfilePanel); } private void copyRightToLeft() throws DatabaseException { copyFiles(rightProfilePanel, leftProfilePanel); } public void copyFiles(AbstractProfileBase sourceProfile, ProfilePanel targetPanel, List<ArcCopyFile> fileList) throws DatabaseException { CopyJob job = new CopyJob(sourceProfile, targetPanel.getSelectedProfile(), fileList); configureJob(job); copyFiles(job, fileList.toArray()); targetPanel.refreshPathAndFileList(); } public void copyFiles(ProfilePanel sourcePanel, ProfilePanel targetPanel) throws DatabaseException { CopyJob job = (CopyJob) getCurrentJob(sourcePanel, targetPanel); configureJob(job); copyFiles(job, sourcePanel.getSelectedFiles()); } public void copyFiles(CopyJob job, Object[] selectedObjectArray) { try { // make sure a local file has been selected if (selectedObjectArray.length > 0) { JobDialog.openNewJob(job); } } catch (JobAlreadyOpenException jaoe) { JOptionPane.showMessageDialog(this, "Another job is already open.\nOnly one job may be open at a time.", "Error", JOptionPane.ERROR_MESSAGE); } catch (Exception e1) { String msg = DBUtils.getErrorMessage("An unexpected error occurred", e1); LOG.log(Level.WARNING, msg, e1); GUIHelper.showMessageDialog(this, msg, "Error", JOptionPane.ERROR_MESSAGE); } finally { setCursor(normalCursor); } } public static void main(String[] args) { try { for (Map.Entry<Object, Object> prop : System.getProperties().entrySet()) { LOG.log(Level.INFO, "System Property: " + prop.getKey() + "=" + prop.getValue()); } PlasticXPLookAndFeel.setPlasticTheme(new ExperienceBlue()); PlasticLookAndFeel.setPlasticTheme(new ExperienceBlue()); UIManager.setLookAndFeel(new PlasticXPLookAndFeel()); // Change label texts per UI bug #21966 UIManager.put(FILE_CHOOSER_LOOK_IN_LABEL_TEXT_PROPERTY, UIManager.getString(FILE_CHOOSER_LOOK_IN_LABEL_TEXT_PROPERTY).replace(":", "")); UIManager.put(FILE_CHOOSER_FILE_NAME_LABEL_TEXT_PROPERTY, UIManager.getString(FILE_CHOOSER_FILE_NAME_LABEL_TEXT_PROPERTY).replace(":", "")); UIManager.put(FILE_CHOOSER_FILES_OF_TYPE_LABEL_TEXT_PROPERTY, UIManager.getString(FILE_CHOOSER_FILES_OF_TYPE_LABEL_TEXT_PROPERTY).replace(":", "")); } catch (Exception e) { LOG.warning("" + e); throw new RuntimeException(e); } SplashDialog splash = new SplashDialog(); try { validateLaunchOK(splash); upgrade(splash); new HCPDataMigrator(splash); } catch (StorageAdapterException e) { LOG.warning("" + e); throw new RuntimeException(e); } } private static void upgrade(final SplashDialog splashDialog) { final String failureDialogTitle = PRODUCT_NAME + " Fatal Error"; try { int compare = DatabaseResourceManager.compareCurrentVersionToDbVersion(); if (compare == 0) { // versions are the same; no action required } else if (compare < 0) { // database version later than code version; can't run String msg = String.format( "The %1$s database has already been upgraded to a more recent version than is supported by this version of %1$s. Please use a more recent version of %1$s.", PRODUCT_NAME); LOG.log(Level.SEVERE, msg); GUIHelper.showMessageDialog(splashDialog, msg, failureDialogTitle, JOptionPane.ERROR_MESSAGE); System.exit(-1); } else { // the database needs upgrading splashDialog.setAlwaysOnTop(false); // splashDialog prevents pleaseWaitDialog from // displaying if it is set to always on top final NoUserControlMessageDialog pleaseWaitDialog = new NoUserControlMessageDialog(splashDialog, String.format("Upgrading %s Database", PRODUCT_NAME), String.format("Upgrading the %s database, please wait.", PRODUCT_NAME)); pleaseWaitDialog.setAlwaysOnTop(true); SwingWorker sw = new SwingWorker() { private String finishMsg = String.format("Completed upgrading the %s database", PRODUCT_NAME); private String finishTitle = String.format("%s Upgrade Complete", PRODUCT_NAME); private boolean isError = false; private int msgDisplayMs = 5000; protected Object doInBackground() throws Exception { try { do { try { Thread.sleep(1000); } catch (Exception ignore) { } // wait 1 second for wait message to display } while (!pleaseWaitDialog.isVisible()); DatabaseResourceManager.upgradeDatabase(); } catch (NonFatalDatabaseException e) { finishMsg = DBUtils.getErrorMessage(String .format("A partial error occurred upgrading the %s database", PRODUCT_NAME), e); finishMsg += "\n\nOne or more saved jobs may not be usable."; msgDisplayMs = -1; // display until user clicks ok LOG.log(Level.WARNING, finishMsg, e); } catch (Exception e) { finishMsg = DBUtils.getErrorMessage( String.format("A fatal error occurred upgrading the %s database", PRODUCT_NAME), e); finishMsg += "\n\nDelete the database to use this version of " + PRODUCT_NAME; finishTitle = failureDialogTitle; isError = true; LOG.log(Level.SEVERE, finishMsg, e); } return null; } protected void done() { if (isError) { GUIHelper.showMessageDialog(splashDialog, finishMsg, finishTitle, JOptionPane.ERROR_MESSAGE); System.exit(-1); } else { // we must display the "upgrade complete" dialog on top of the "upgrade // in progress" dialog. // If we call pleaseWaitDialog.setVisible(false) prior to the // GUIHelper.showMessageDialog() completing, then // the call to pleaseWaitDialog.setVisible(true) below completes before // the GUIHelper.showMessageDialog() completes, // and therefore we set splash dialog on top and return from this method // prior to the "upgrade completed" dialog going away, // which is not what we want. GUIHelper.showMessageDialog(msgDisplayMs, pleaseWaitDialog, true, finishMsg, finishTitle, JOptionPane.INFORMATION_MESSAGE); pleaseWaitDialog.setVisible(false); } } }; sw.execute(); pleaseWaitDialog.setVisible(true); // this will not return until the dialog is no // longer visible splashDialog.setAlwaysOnTop(true); } } catch (Exception e) { String msg = "A fatal upgrade error occurred: " + e.getMessage(); LOG.log(Level.SEVERE, msg, e); GUIHelper.showMessageDialog(splashDialog, msg, failureDialogTitle, JOptionPane.ERROR_MESSAGE); System.exit(-1); } } private static void validateLaunchOK(final SplashDialog splashDialog) { final String failureDialogTitle = PRODUCT_NAME + " Fatal Error"; try { ConfigurationHelper.validateLaunchOK(false); // don't do upgrade here; we'll do it // separately } catch (Exception e) { String msg = "A fatal error occurred: " + e.getMessage(); LOG.log(Level.SEVERE, msg, e); GUIHelper.showMessageDialog(splashDialog, msg, failureDialogTitle, JOptionPane.ERROR_MESSAGE); System.exit(-1); } } private void shutdown() { DatabaseResourceManager.shutdownDB(); System.exit(0); } protected void openObjectAction() { ProfilePanel panel = getActivePanel(); if (panel != null && doesFilePanelHaveSingleSelection(panel)) { panel.openSelectedRow(); } } protected void deleteObjectAction() { ProfilePanel panel = getActivePanel(); if (panel != null && doesFilePanelHaveSelection(panel)) { panel.deleteSelectedRows(); } } protected void setMetadataObjectAction() { ProfilePanel panel = getActivePanel(); if (panel != null && doesFilePanelHaveSelection(panel)) { panel.setMetadataOnSelectedRows(); } } protected void renameObjectAction() { ProfilePanel panel = getActivePanel(); if (panel != null && doesFilePanelHaveSingleSelection(panel)) { panel.renameSelectedRow(); } } protected void objectPropertiesAction() { ProfilePanel panel = getActivePanel(); if (panel != null && doesFilePanelHaveSingleSelection(panel)) { panel.displaySelectedObjectProperties(); } } public void selectionFromPanel(final ProfilePanel panelWithSelection) { // Enable/Disable buttons and menu options if (rightProfilePanel != panelWithSelection) { rightProfilePanel.clearSelection(); } if (leftProfilePanel != panelWithSelection) { leftProfilePanel.clearSelection(); } updateLockable(); } /** * Updates the put and get buttons The put button is enabled if neither panel is locked, the * left side has a selection of at least one non-deleted file and the right side is not read * only and there is no open job The get button is enabled if neither panel is locked, the right * side has a selection of at least one non-deleted file and the left side is not read only and * there is no open job */ private void updateButtons() { boolean locked = leftProfilePanel.isLocked() || rightProfilePanel.isLocked() || JobDialog.isOpen(); boolean leftSelection = leftProfilePanel.getNonDeletedSelectedFileCount() > 0; putButton.setEnabled(!locked && leftSelection && !rightProfilePanel.isSelectionReadOnly()); boolean rightSelection = rightProfilePanel.getNonDeletedSelectedFileCount() > 0; getButton.setEnabled(!locked && rightSelection && !leftProfilePanel.isSelectionReadOnly()); } public void saveSelectedProfile(ProfilePanel panel, String profileName) { try { if (panel == leftProfilePanel) { ConfigurationHelper.setUserProperty(LEFT_PROFILE_NAME, profileName); } else if (panel == rightProfilePanel) { ConfigurationHelper.setUserProperty(RIGHT_PROFILE_NAME, profileName); } } catch (ConfigurationException e) { LOG.log(Level.WARNING, "Could not save selected profile", e); } } /** * Updates the file menu Each item is enabled based on the active panel, the current selected * file and whether there are one or more selected files Each lockable menu item is locked if * either panel is locked or there is an open job dialog */ private void updateFileMenu() { if (!SwingUtilities.isEventDispatchThread()) { String errMsg = "updateFileMenu is not on the EDT but it should be"; IllegalStateException ex = new IllegalStateException(errMsg); LOG.log(Level.SEVERE, errMsg, ex); throw ex; } ProfilePanel panel = getActivePanel(); ArcMoverFile selectedFile = null; if (panel != null) { selectedFile = panel.getSelectedFile(); } boolean single = doesFilePanelHaveSingleSelection(panel); setOpenMenuItemEnabled(panel, selectedFile, single); setDeleteMenuItemEnabled(panel, selectedFile, single); setSetMetadataMenuItemEnabled(panel, selectedFile, single); setRenameMenuItemEnabled(panel, selectedFile, single); setPropertiesMenuItemEnabled(panel, selectedFile, single); boolean locked = leftProfilePanel.isLocked() || rightProfilePanel.isLocked() || JobDialog.isOpen(); for (JMenuItem item : lockableMenuItems) { item.setEnabled(!locked); } } private ProfilePanel getActivePanel() { ProfilePanel activePanel = null; if (leftProfilePanel.getSelectedRowCount() > 0) { activePanel = leftProfilePanel; } else if (rightProfilePanel.getSelectedRowCount() > 0) { activePanel = rightProfilePanel; } return activePanel; } protected void setOpenMenuItemEnabled(ProfilePanel panel, ArcMoverFile selectedFile, boolean single) { openMenuItem .setEnabled(panel != null && !panel.isLocked() && panel.supportsOpenAction(selectedFile, single)); } /** * Sets the delete menu item Active if there is an active panel, it is unlocked, it supports * delete and the job dialog is not open * * @param panel * Current active panel * @param selectedFile * Current selected file * @param single * Whether there is one or more selected files */ protected void setDeleteMenuItemEnabled(ProfilePanel panel, ArcMoverFile selectedFile, boolean single) { deleteMenuItem.setEnabled(!JobDialog.isOpen() && panel != null && !panel.isLocked() && panel.supportsDeleteAction(selectedFile, single)); } /** * Sets the delete menu item Active if there is an active panel, it is unlocked, it supports * delete and the job dialog is not open * * @param panel * Current active panel * @param selectedFile * Current selected file * @param single * Whether there is one or more selected files */ protected void setSetMetadataMenuItemEnabled(ProfilePanel panel, ArcMoverFile selectedFile, boolean single) { setMetadataMenuItem.setEnabled(!JobDialog.isOpen() && panel != null && !panel.isLocked() && panel.supportsSetMetadataAction(selectedFile, single)); } /** * Sets the rename menu item Active if there is an active panel, it is unlocked, it supports * rename and the job dialog is not open * * @param panel * Current active panel * @param selectedFile * Current selected file * @param single * Whether there is one or more selected files */ protected void setRenameMenuItemEnabled(ProfilePanel panel, ArcMoverFile selectedFile, boolean single) { renameMenuItem.setEnabled(!JobDialog.isOpen() && panel != null && !panel.isLocked() && panel.supportsRenameAction(selectedFile, single)); } protected void setPropertiesMenuItemEnabled(ProfilePanel panel, ArcMoverFile selectedFile, boolean single) { propertiesMenuItem.setEnabled( panel != null && !panel.isLocked() && panel.supportsPropertiesAction(selectedFile, single)); } /** * Whether there is at least one file selected * * @param profilePanel * the panel to check * @return whether at least one file is selected */ protected boolean doesFilePanelHaveSelection(ProfilePanel profilePanel) { return (profilePanel != null && profilePanel.getSelectedRowCount() > 0); } /** * Whether there is exactly one file selected * * @param profilePanel * the panel to check * @return whether exactly one file is selected */ private boolean doesFilePanelHaveSingleSelection(ProfilePanel profilePanel) { return (profilePanel != null && profilePanel.getSelectedRowCount() == 1); } public static void showMigratorInstance() { getInstance().showMigrator(); } /** * Shows the migrator instance. This method makes a best attempt at bringing the migrator to the * front, working around some issues with Swing. */ public void showMigrator() { showMigrator(true); } /** * Factored out the invocation of the self-destructive dialog because it was stealing focus * during window closing. Normally it should be safe though. * * @param invoke * Whether to use the self-destructive dialog or not */ private void showMigrator(boolean invoke) { updateLockable(); setVisible(true); // Un-iconify if (getState() == Frame.ICONIFIED) { setState(Frame.NORMAL); } toFront(); requestFocus(); final HCPDataMigrator migrator = this; if (invoke) { SelfDestructiveDialog.invoke(migrator); } } /** * Refreshes each panel, but only if it's unlocked */ public void refreshPanels() { if (!leftProfilePanel.isLocked()) { leftProfilePanel.refreshPathAndFileList(); } if (!rightProfilePanel.isLocked()) { rightProfilePanel.refreshPathAndFileList(); } } /** * Refreshes each panel where it's using the same profile and current directory on that panel * matches the given directory, where version lists count as a directory match * * @param profile * The profile to look for * @param directory * The directory to look for */ public void refreshMatchingPanels(AbstractProfileBase profile, ArcMoverDirectory directory) { final String dirPath; if (directory.isVersionList()) { dirPath = directory.getParent().getPath(); } else { dirPath = directory.getPath(); } if (!leftProfilePanel.isLocked() && profile.equals(leftProfilePanel.getSelectedProfile())) { final String leftDirPath; final ArcMoverDirectory leftDir = leftProfilePanel.getCurrentDirectory(); if (leftDir.isVersionList()) { leftDirPath = leftDir.getParent().getPath(); } else { leftDirPath = leftDir.getPath(); } if (dirPath.equals(leftDirPath)) { leftProfilePanel.refreshPathAndFileList(); } } if (!rightProfilePanel.isLocked() && profile.equals(rightProfilePanel.getSelectedProfile())) { final String rightDirPath; final ArcMoverDirectory rightDir = rightProfilePanel.getCurrentDirectory(); if (rightDir.isVersionList()) { rightDirPath = rightDir.getParent().getPath(); } else { rightDirPath = rightDir.getPath(); } if (dirPath.equals(rightDirPath)) { rightProfilePanel.refreshPathAndFileList(); } } } }