/* 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.merge.MergeFrame; import com.qumasoft.guitools.qwin.QWinFrame; import com.qumasoft.guitools.qwin.QWinUtility; import com.qumasoft.qvcslib.ClientExpansionContext; import com.qumasoft.qvcslib.MergedInfoInterface; import com.qumasoft.qvcslib.QVCSException; import com.qumasoft.qvcslib.QVCSOperationException; import com.qumasoft.qvcslib.UserLocationProperties; import com.qumasoft.qvcslib.Utility; import com.qumasoft.qvcslib.WorkfileDigestManager; import com.qumasoft.qvcslib.WorkfileInfo; import java.awt.HeadlessException; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.SwingUtilities; /** * Visual merge operation. * @author Jim Voris */ public class OperationVisualMerge extends OperationBaseClass { /** * Create a visual merge operation. * @param fileTable the file table. * @param serverName the server name. * @param projectName the project name. * @param viewName the view name. * @param userLocationProperties user location properties. */ public OperationVisualMerge(JTable fileTable, String serverName, String projectName, String viewName, UserLocationProperties userLocationProperties) { super(fileTable, serverName, projectName, viewName, userLocationProperties); } @Override public void executeOperation() { if (getFileTable() != null) { try { final List mergedInfoArray = getSelectedFiles(); if (mergedInfoArray.size() == 1) { // Run the update on the Swing thread. Runnable later = new Runnable() { @Override public void run() { Iterator it = mergedInfoArray.iterator(); while (it.hasNext()) { MergedInfoInterface mergedInfo = (MergedInfoInterface) it.next(); if ((!mergedInfo.getAttributes().getIsBinaryfile()) && (mergedInfo.getStatusIndex() == MergedInfoInterface.MERGE_REQUIRED_STATUS_INDEX)) { try { visualMerge(mergedInfo); } catch (QVCSOperationException e) { JOptionPane.showMessageDialog(QWinFrame.getQWinFrame(), e.getLocalizedMessage(), "Visual merge failed!", JOptionPane.WARNING_MESSAGE); } catch (IOException e) { QWinUtility.logProblem(Level.SEVERE, Utility.expandStackTraceToString(e)); } } else { if (mergedInfo.getAttributes().getIsBinaryfile()) { JOptionPane.showMessageDialog(QWinFrame.getQWinFrame(), "Merging for binary files is not supported.", "Binary merge not supported", JOptionPane.WARNING_MESSAGE); } else { if (mergedInfo.getStatusIndex() != MergedInfoInterface.MERGE_REQUIRED_STATUS_INDEX) { JOptionPane.showMessageDialog(QWinFrame.getQWinFrame(), "Visual merge is only supported for files with 'Merged Required' status.", "Merge not required", JOptionPane.WARNING_MESSAGE); } } } } } }; SwingUtilities.invokeLater(later); } else { JOptionPane.showMessageDialog(QWinFrame.getQWinFrame(), "Please select just a single file to merge.", "Merge one file only", JOptionPane.INFORMATION_MESSAGE); } } catch (HeadlessException e) { QWinUtility.logProblem(Level.WARNING, "OperationMergeFile caught exception: " + e.getClass().toString() + " " + e.getLocalizedMessage()); QWinUtility.logProblem(Level.WARNING, Utility.expandStackTraceToString(e)); } } } private void visualMerge(MergedInfoInterface mergedInfo) throws IOException, QVCSOperationException { // Get the base revision string for the current workfile. String baseRevisionString = WorkfileDigestManager.getInstance().getDigestWorkfileInfo(mergedInfo.getWorkfileInfo()).getWorkfileRevisionString(); String currentDefaultRevisionString = mergedInfo.getDefaultRevisionString(); // Get workfile buffer... not keyword expanded. byte[] baseBuffer = mergedInfo.getRevisionAsByteArray(baseRevisionString); byte[] defaultBuffer = mergedInfo.getRevisionAsByteArray(currentDefaultRevisionString); // Create a new workfileInfo that we use in the case that the user saves the result of the merge... WorkfileInfo workfileInfo = new WorkfileInfo(mergedInfo.getFullWorkfileName(), mergedInfo.getAttributes().getIsExpandKeywords(), mergedInfo.getAttributes().getIsBinaryfile(), getProjectName()); Date now = new Date(); workfileInfo.setFetchedDate(now.getTime()); workfileInfo.setWorkfileRevisionString(currentDefaultRevisionString); int baseBufferRevisionIndex = mergedInfo.getLogfileInfo().getRevisionInformation().getRevisionIndex(baseRevisionString); int defaultBufferRevisionIndex = mergedInfo.getLogfileInfo().getRevisionInformation().getRevisionIndex(currentDefaultRevisionString); if ((baseBuffer != null) && (defaultBuffer != null)) { ClientExpansionContext baseContext = new ClientExpansionContext(getServerName(), QWinFrame.getQWinFrame().getUserProperties(), QWinFrame.getQWinFrame().getUserLocationProperties(), baseBufferRevisionIndex, null, true); File expandedBaseBufferFile = Utility.expandBuffer(baseBuffer, mergedInfo, baseContext); ClientExpansionContext defaultContext = new ClientExpansionContext(getServerName(), QWinFrame.getQWinFrame().getUserProperties(), QWinFrame.getQWinFrame().getUserLocationProperties(), defaultBufferRevisionIndex, null, true); File expandedDefaultBufferFile = Utility.expandBuffer(defaultBuffer, mergedInfo, defaultContext); File currentWorkFile = mergedInfo.getWorkfile(); File afterMergeWorkFile = new File(currentWorkFile.getCanonicalPath() + ".qvcsAfterMerge"); MergeFrame mergeFrame = new MergeFrame(QWinFrame.getQWinFrame()); mergeFrame.mergeFiles(expandedBaseBufferFile.getCanonicalPath(), expandedDefaultBufferFile.getCanonicalPath(), mergedInfo.getShortWorkfileName() + " Revision: " + currentDefaultRevisionString, currentWorkFile.getCanonicalPath(), mergedInfo.getShortWorkfileName() + " Revision: " + baseRevisionString + " plus your edits.", afterMergeWorkFile.getCanonicalPath(), "Merged Result: " + mergedInfo.getShortWorkfileName(), this, mergedInfo, workfileInfo, defaultBuffer); } } /** * Update the workfile info as a result of the merge. * @param mergedInfo the file we're working on. * @param workfileInfo the workfile info. * @param defaultWorkfileBuffer the bytes of the default workfile for the given file. */ public void updateWorkfileInfo(final MergedInfoInterface mergedInfo, final WorkfileInfo workfileInfo, final byte[] defaultWorkfileBuffer) { // Run the update on the Swing thread. Runnable later = new Runnable() { @Override public void run() { try { // Update the Workfile digest manager. WorkfileDigestManager.getInstance().updateWorkfileDigestForMerge(defaultWorkfileBuffer, workfileInfo, mergedInfo.getArchiveDirManager().getProjectProperties()); QWinFrame.getQWinFrame().refreshCurrentView(); } catch (QVCSException e) { QWinUtility.logProblem(Level.WARNING, Utility.expandStackTraceToString(e)); } } }; SwingUtilities.invokeLater(later); } }