/* Copyright 2004-2014 Jim Voris * * 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.qumasoft.guitools.qwin.operation; import com.qumasoft.guitools.qwin.dialog.AutoAddFilesDialog; import com.qumasoft.guitools.qwin.dialog.ParentChildProgressDialog; import com.qumasoft.guitools.qwin.dialog.ProgressDialog; import com.qumasoft.guitools.qwin.ProgressDialogInterface; import com.qumasoft.guitools.qwin.ProjectTreeControl; import com.qumasoft.guitools.qwin.QWinFrame; import com.qumasoft.guitools.qwin.QWinUtility; import com.qumasoft.qvcslib.AbstractProjectProperties; import com.qumasoft.qvcslib.ArchiveDirManagerInterface; import com.qumasoft.qvcslib.ClientTransactionManager; import com.qumasoft.qvcslib.DirectoryCoordinate; import com.qumasoft.qvcslib.DirectoryManagerFactory; import com.qumasoft.qvcslib.DirectoryManagerInterface; import com.qumasoft.qvcslib.commandargs.CreateArchiveCommandArgs; import com.qumasoft.qvcslib.MergedInfoInterface; import com.qumasoft.qvcslib.QVCSException; import com.qumasoft.qvcslib.ServerProperties; import com.qumasoft.qvcslib.UserLocationProperties; import com.qumasoft.qvcslib.Utility; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.logging.Level; /** * Operation auto-add files. * @author Jim Voris */ public final class OperationAutoAddFiles extends OperationBaseClass { private final String appendedPath; private final AbstractProjectProperties projectProperties; private final File currentWorkfileDirectory; private final String currentWorkfileDirectoryPath; /** * Auto add files. * * @param serverName the server name. * @param projectName the project name. * @param viewName the view name. * @param path the appended path. * @param userLocationProperties user location properties. * @param projectProps project properties. * @param currWorkfileDirectory a File that represents the current workfile directory. */ public OperationAutoAddFiles(String serverName, String projectName, String viewName, String path, UserLocationProperties userLocationProperties, AbstractProjectProperties projectProps, File currWorkfileDirectory) { super(null, serverName, projectName, viewName, userLocationProperties); appendedPath = path; projectProperties = projectProps; currentWorkfileDirectory = currWorkfileDirectory; currentWorkfileDirectoryPath = currWorkfileDirectory.getAbsolutePath(); } String getAppendedPath() { return appendedPath; } String getProjectType() { return projectProperties.getProjectType(); } AbstractProjectProperties getProjectProperties() { return projectProperties; } @Override public void executeOperation() { AutoAddFilesDialog autoAddFilesDialog = new AutoAddFilesDialog(QWinFrame.getQWinFrame(), true, this); autoAddFilesDialog.setVisible(true); } /** * Process the dialog choices. * @param recurseDirectories should we recurse directories; true for yes, false for no. * @param includeExtensions the extensions (comma separated) to include. * @param excludeExtensions the extensions (comma separated) to exclude. * @param createAllDirectories should we add an archive directory for any workfile directory (even if we don't add any files from that directory), true means yes, * false means no. */ public void processDialogResult(boolean recurseDirectories, String includeExtensions, String excludeExtensions, boolean createAllDirectories) { final boolean fRecurseDirectories = recurseDirectories; final String[] fIncludeExtensions = buildExtensionList(includeExtensions); final String[] fExcludeExtensions = buildExtensionList(excludeExtensions); final boolean fCreateAllDirectories = createAllDirectories; final Set<String> fCreatedDirectoriesSet = new HashSet<>(); // These values are invariant over the entire add process. Capturing them here allows things to // work even if the user navigates off the current node. final String fServerName = getServerName(); final AbstractProjectProperties fProjectProperties = getProjectProperties(); final ProgressDialog fProgressDialog = createProgressDialog("Add Files to source control", 10); fProgressDialog.setAutoClose(false); final ParentChildProgressDialog fParentProgressDialog = createParentProgressDialog("Add Files to source control", 10); fParentProgressDialog.setAutoClose(false); final ServerProperties fServerProperties = ProjectTreeControl.getInstance().getActiveServer(); Runnable worker = new Runnable() { @Override public void run() { int transactionID = 0; try { transactionID = ClientTransactionManager.getInstance().sendBeginTransaction(fServerProperties); if (!fRecurseDirectories) { // We don't have to recurse directories. This is the simpler case // We just need to look for workfiles in the current directory // that match the criteria defined by the user. If the given // file/files don't yet have an archive, then we need to create // an archive for that file. processForNonRecursion(fIncludeExtensions, fExcludeExtensions, fServerName, fProjectProperties, fProgressDialog, fCreatedDirectoriesSet); } else { // We have to recurse directories. processForRecursion(fIncludeExtensions, fExcludeExtensions, fCreateAllDirectories, fServerName, fProjectProperties, fParentProgressDialog, fCreatedDirectoriesSet); } } finally { if (fRecurseDirectories) { fParentProgressDialog.close(); } else { fProgressDialog.close(); } ClientTransactionManager.getInstance().sendEndTransaction(fServerProperties, transactionID); } } }; // Put all this on a separate worker thread. new Thread(worker).start(); } private void processForNonRecursion(String[] includeExtensions, String[] excludeExtensions, String serverName, AbstractProjectProperties projectProps, ProgressDialogInterface progressDialog, Set<String> createdDirectoriesSet) { if (includeExtensions != null) { processIncludeExtensions(includeExtensions, "", true, serverName, projectProps, progressDialog, createdDirectoriesSet); } else if (excludeExtensions != null) { processExcludeExtensions(excludeExtensions, "", true, serverName, projectProps, progressDialog, createdDirectoriesSet); } else { processAllExtensions("", true, serverName, projectProps, progressDialog, createdDirectoriesSet); } } private void processForRecursion(String[] includeExtensions, String[] excludeExtensions, boolean createAllDirectories, String serverName, AbstractProjectProperties projectProps, final ParentChildProgressDialog progressDialog, Set<String> createdDirectoriesSet) { // First create a collection of all the subdirectories beneath the // current directory. Collection subDirectories = createSubdirectoryCollection(new ArrayList<String>(), currentWorkfileDirectory.getAbsolutePath()); // Now iterate over that collection, creating the archives for // the requested files. Iterator it = subDirectories.iterator(); int max = subDirectories.size() + 1; int count = 0; OperationBaseClass.initParentChildProgressDialog("Adding files", 0, max, progressDialog); while (it.hasNext() && !progressDialog.getIsCancelled()) { String subDirectory = (String) it.next(); updateParentChildProgressDialog(count++, "Adding files for directory " + subDirectory, progressDialog); if (includeExtensions != null) { processIncludeExtensions(includeExtensions, subDirectory, createAllDirectories, serverName, projectProps, progressDialog, createdDirectoriesSet); } else if (excludeExtensions != null) { processExcludeExtensions(excludeExtensions, subDirectory, createAllDirectories, serverName, projectProps, progressDialog, createdDirectoriesSet); } else { processAllExtensions(subDirectory, createAllDirectories, serverName, projectProps, progressDialog, createdDirectoriesSet); } } // And finish up by processing the current directory. processForNonRecursion(includeExtensions, excludeExtensions, serverName, projectProps, progressDialog, createdDirectoriesSet); } private void processIncludeExtensions(String[] extensions, String recursedDirectoryName, boolean createAllDirectories, String serverName, AbstractProjectProperties projectProps, ProgressDialogInterface progressDialog, Set<String> createdDirectoriesSet) { try { String appendPath; String workfilePath; if (getAppendedPath().length() > 0) { if (recursedDirectoryName.length() > 0) { appendPath = Utility.endsWithoutPathSeparator(getAppendedPath()) + File.separator + recursedDirectoryName; } else { appendPath = getAppendedPath(); } } else { appendPath = recursedDirectoryName; } if (recursedDirectoryName.length() > 0) { workfilePath = Utility.endsWithoutPathSeparator(currentWorkfileDirectory.getAbsolutePath()) + File.separator + recursedDirectoryName; } else { workfilePath = currentWorkfileDirectory.getAbsolutePath(); } String userName = DirectoryManagerFactory.getInstance().getServerUsername(serverName); DirectoryCoordinate directoryCoordinate = new DirectoryCoordinate(getProjectName(), getViewName(), appendPath); DirectoryManagerInterface directoryManager = DirectoryManagerFactory.getInstance().getDirectoryManager(serverName, directoryCoordinate, getProjectType(), projectProps, workfilePath, null, false); if (createAllDirectories) { createArchiveDirectory(directoryManager, createdDirectoriesSet); } // Merge the managers so we'll have a collection to operate on... directoryManager.mergeManagers(); // Get the list of mergedInfo objects we need to operate on... Iterator it = directoryManager.getMergedInfoCollection().iterator(); int size = directoryManager.getMergedInfoCollection().size(); OperationBaseClass.initProgressDialog("Directory: " + workfilePath, 0, size, progressDialog); int createCount = 0; int k = 0; while (it.hasNext() && !progressDialog.getIsCancelled()) { MergedInfoInterface mergedInfo = (MergedInfoInterface) it.next(); if (mergedInfo.getArchiveInfo() == null) { for (String extension : extensions) { String shortWorkfileName = mergedInfo.getShortWorkfileName(); if (projectProps.getIgnoreCaseFlag()) { shortWorkfileName = shortWorkfileName.toLowerCase(); } if (shortWorkfileName.endsWith(extension)) { createArchive(directoryManager, mergedInfo, userName, createAllDirectories, createCount++, createdDirectoriesSet); updateProgressDialog(k, "Creating archive for: " + mergedInfo.getShortWorkfileName(), progressDialog); break; } } } k++; } } catch (QVCSException e) { QWinUtility.logProblem(Level.WARNING, e.getLocalizedMessage()); } } private void processExcludeExtensions(String[] extensions, String recursedDirectoryName, boolean createAllDirectories, String serverName, AbstractProjectProperties projectProps, ProgressDialogInterface progressDialog, Set<String> createdDirectoriesSet) { try { String appendPath; String workfilePath; if (getAppendedPath().length() > 0) { if (recursedDirectoryName.length() > 0) { appendPath = Utility.endsWithoutPathSeparator(getAppendedPath()) + File.separator + recursedDirectoryName; } else { appendPath = getAppendedPath(); } } else { appendPath = recursedDirectoryName; } if (recursedDirectoryName.length() > 0) { workfilePath = Utility.endsWithoutPathSeparator(currentWorkfileDirectory.getAbsolutePath()) + File.separator + recursedDirectoryName; } else { workfilePath = currentWorkfileDirectory.getAbsolutePath(); } String userName = DirectoryManagerFactory.getInstance().getServerUsername(serverName); DirectoryCoordinate directoryCoordinate = new DirectoryCoordinate(getProjectName(), getViewName(), appendPath); DirectoryManagerInterface directoryManager = DirectoryManagerFactory.getInstance().getDirectoryManager(serverName, directoryCoordinate, getProjectType(), projectProps, workfilePath, null, false); if (createAllDirectories) { createArchiveDirectory(directoryManager, createdDirectoriesSet); } // Merge the managers so we'll have a collection to operate on... directoryManager.mergeManagers(); // Build the list of mergedInfo objects we need to operate on... Iterator it = directoryManager.getMergedInfoCollection().iterator(); int size = directoryManager.getMergedInfoCollection().size(); OperationBaseClass.initProgressDialog("Directory: " + workfilePath, 0, size, progressDialog); int createCount = 0; int k = 0; while (it.hasNext() && !progressDialog.getIsCancelled()) { MergedInfoInterface mergedInfo = (MergedInfoInterface) it.next(); if (mergedInfo.getArchiveInfo() == null) { // There is no archive for this one yet... // See if it matches the include extension filter. boolean excludedExtension = false; for (String extension : extensions) { String shortWorkfileName = mergedInfo.getShortWorkfileName(); if (projectProps.getIgnoreCaseFlag()) { shortWorkfileName = shortWorkfileName.toLowerCase(); } if (shortWorkfileName.endsWith(extension)) { excludedExtension = true; break; } } // If it's not an excluded extension... if (!excludedExtension) { createArchive(directoryManager, mergedInfo, userName, createAllDirectories, createCount++, createdDirectoriesSet); OperationBaseClass.updateProgressDialog(k, mergedInfo.getShortWorkfileName(), progressDialog); } } k++; } } catch (QVCSException e) { QWinUtility.logProblem(Level.WARNING, e.getLocalizedMessage()); } } private void processAllExtensions(String recursedDirectoryName, boolean createAllDirectories, String serverName, AbstractProjectProperties projectProps, final ProgressDialogInterface progressDialog, Set<String> createdDirectoriesSet) { try { String appendPath; String workfilePath; if (getAppendedPath().length() > 0) { if (recursedDirectoryName.length() > 0) { appendPath = Utility.endsWithoutPathSeparator(getAppendedPath()) + File.separator + recursedDirectoryName; } else { appendPath = getAppendedPath(); } } else { appendPath = recursedDirectoryName; } if (recursedDirectoryName.length() > 0) { workfilePath = Utility.endsWithoutPathSeparator(currentWorkfileDirectory.getAbsolutePath()) + File.separator + recursedDirectoryName; } else { workfilePath = currentWorkfileDirectory.getAbsolutePath(); } String userName = DirectoryManagerFactory.getInstance().getServerUsername(serverName); DirectoryCoordinate directoryCoordinate = new DirectoryCoordinate(getProjectName(), getViewName(), appendPath); DirectoryManagerInterface directoryManager = DirectoryManagerFactory.getInstance().getDirectoryManager(serverName, directoryCoordinate, getProjectType(), projectProps, workfilePath, null, false); if (createAllDirectories) { createArchiveDirectory(directoryManager, createdDirectoriesSet); } // Merge the managers so we'll have a collection to operate on... directoryManager.mergeManagers(); // Get the list of mergedInfo objects we need to operate on... Iterator it = directoryManager.getMergedInfoCollection().iterator(); int size = directoryManager.getMergedInfoCollection().size(); OperationBaseClass.initProgressDialog("Directory: " + workfilePath, 0, size, progressDialog); int k = 0; int createCount = 0; while (it.hasNext() && !progressDialog.getIsCancelled()) { MergedInfoInterface mergedInfo = (MergedInfoInterface) it.next(); if (mergedInfo.getArchiveInfo() == null) { // There is no archive for this one yet... createArchive(directoryManager, mergedInfo, userName, createAllDirectories, createCount++, createdDirectoriesSet); OperationBaseClass.updateProgressDialog(k, mergedInfo.getShortWorkfileName(), progressDialog); } k++; } } catch (QVCSException e) { QWinUtility.logProblem(Level.WARNING, e.getLocalizedMessage()); } } private void createArchive(DirectoryManagerInterface directoryManager, MergedInfoInterface mergedInfo, String userName, boolean createAllDirectories, int createCount, Set<String> createdDirectoriesSet) { try { // Create the archive directory if it hasn't been created yet... if ((!createAllDirectories) && (createCount == 0)) { createArchiveDirectory(directoryManager, createdDirectoriesSet); } CreateArchiveCommandArgs commandLineArgs = new CreateArchiveCommandArgs(); commandLineArgs.setArchiveDescription("Auto-Added"); commandLineArgs.setCommentPrefix(""); commandLineArgs.setInputfileTimeStamp(new Date(mergedInfo.getWorkfileInfo().getWorkfile().lastModified())); commandLineArgs.setLockFlag(false); commandLineArgs.setUserName(userName); commandLineArgs.setWorkfileName(mergedInfo.getShortWorkfileName()); QWinUtility.logProblem(Level.INFO, "Requesting creation of archive for:" + mergedInfo.getFullWorkfileName()); // And create the archive directoryManager.createArchive(commandLineArgs, mergedInfo.getFullWorkfileName()); } catch (IOException | QVCSException e) { QWinUtility.logProblem(Level.WARNING, e.getLocalizedMessage()); } } private String[] buildExtensionList(String extensions) { String[] extensionList = null; if (extensions != null) { // Build the list of extensions // This splits based on commas, or white space. extensionList = extensions.split("[,\\s]"); } return extensionList; } private Collection createSubdirectoryCollection(ArrayList<String> collection, String parentDirectoryName) { File directory = new File(parentDirectoryName); File[] subDirectories = directory.listFiles(new DirectoryFilter()); String currentWorkfileDirectoryPathWithTermination = Utility.endsWithPathSeparator(currentWorkfileDirectoryPath); if (subDirectories != null) { for (File subDirectorie : subDirectories) { String nameToAdd = subDirectorie.getAbsolutePath().substring(currentWorkfileDirectoryPathWithTermination.length()); collection.add(nameToAdd); createSubdirectoryCollection(collection, subDirectorie.getAbsolutePath()); } } return collection; } /** * Create the archive directory if we haven't already requested its creation. * * @param directoryManager * @param createdDirectories the set of directories that we've already created. */ private void createArchiveDirectory(DirectoryManagerInterface directoryManager, Set<String> createdDirectories) { if (!createdDirectories.contains(directoryManager.getAppendedPath())) { createdDirectories.add(directoryManager.getAppendedPath()); ArchiveDirManagerInterface archiveDirManager = directoryManager.getArchiveDirManager(); archiveDirManager.createDirectory(); } } static class DirectoryFilter implements java.io.FilenameFilter { DirectoryFilter() { } @Override public boolean accept(java.io.File dir, String name) { boolean retVal = false; java.io.File file = new java.io.File(dir.getPath(), name); if (file.isDirectory()) { boolean ignoreHiddenDirectoriesFlag = QWinFrame.getQWinFrame().getUserProperties().getIgnoreHiddenDirectoriesFlag(); if (ignoreHiddenDirectoriesFlag) { if (name.startsWith(".")) { retVal = false; } else { retVal = !file.isHidden(); } } else { retVal = true; } } return retVal; } } }