mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
New merge dialog initial implementation
This commit is contained in:
@@ -530,6 +530,9 @@ vcs.enable.partial.changelists.redo.restartRequired=true
|
||||
vcs.skip.single.default.changelist=true
|
||||
vcs.skip.single.default.changelist.description=Don't show changelist node in Local Changes view when only the Default changelist exists
|
||||
|
||||
vcs.new.multiple.file.merge=false
|
||||
vcs.new.multiple.file.merge.description=Use new implementation of multiple files merge dialog
|
||||
|
||||
psi.incremental.reparse.depth.limit=1000
|
||||
psi.deferIconLoading=true
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ public final class VcsConfiguration implements PersistentStateComponent<VcsConfi
|
||||
public boolean UPDATE_GROUP_BY_CHANGELIST = false;
|
||||
public boolean UPDATE_FILTER_BY_SCOPE = false;
|
||||
public boolean SHOW_FILE_HISTORY_AS_TREE = false;
|
||||
public boolean GROUP_MULTIFILE_MERGE_BY_DIRECTORY = false;
|
||||
|
||||
private static final int MAX_STORED_MESSAGES = 25;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.actions.AnnotateToggleAction;
|
||||
@@ -45,6 +46,7 @@ import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vcs.merge.MergeDialogCustomizer;
|
||||
import com.intellij.openapi.vcs.merge.MergeProvider;
|
||||
import com.intellij.openapi.vcs.merge.MultipleFileMergeDialog;
|
||||
import com.intellij.openapi.vcs.merge.MultipleFileMergeDialog2;
|
||||
import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
|
||||
import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor;
|
||||
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
@@ -494,10 +496,18 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
|
||||
@NotNull MergeDialogCustomizer mergeDialogCustomizer) {
|
||||
if (files.isEmpty()) return Collections.emptyList();
|
||||
VfsUtil.markDirtyAndRefresh(false, false, false, ArrayUtil.toObjectArray(files, VirtualFile.class));
|
||||
final MultipleFileMergeDialog fileMergeDialog = new MultipleFileMergeDialog(myProject, files, provider, mergeDialogCustomizer);
|
||||
AppIcon.getInstance().requestAttention(myProject, true);
|
||||
fileMergeDialog.show();
|
||||
return fileMergeDialog.getProcessedFiles();
|
||||
if (Registry.is("vcs.new.multiple.file.merge")) {
|
||||
final MultipleFileMergeDialog2 fileMergeDialog = new MultipleFileMergeDialog2(myProject, files, provider, mergeDialogCustomizer);
|
||||
AppIcon.getInstance().requestAttention(myProject, true);
|
||||
fileMergeDialog.show();
|
||||
return fileMergeDialog.getProcessedFiles();
|
||||
}
|
||||
else {
|
||||
final MultipleFileMergeDialog fileMergeDialog = new MultipleFileMergeDialog(myProject, files, provider, mergeDialogCustomizer);
|
||||
AppIcon.getInstance().requestAttention(myProject, true);
|
||||
fileMergeDialog.show();
|
||||
return fileMergeDialog.getProcessedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
public void openCommittedChangesTab(final AbstractVcs vcs,
|
||||
|
||||
@@ -0,0 +1,468 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.vcs.merge
|
||||
|
||||
import com.intellij.CommonBundle
|
||||
import com.intellij.diff.DiffManager
|
||||
import com.intellij.diff.DiffRequestFactory
|
||||
import com.intellij.diff.InvalidDiffRequestException
|
||||
import com.intellij.diff.merge.MergeRequest
|
||||
import com.intellij.diff.merge.MergeResult
|
||||
import com.intellij.diff.merge.MergeUtil
|
||||
import com.intellij.diff.util.DiffUtil
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ide.presentation.VirtualFilePresentation
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.command.WriteCommandAction.writeCommandAction
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diff.impl.mergeTool.MergeVersion
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ex.ProjectManagerEx
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vcs.VcsBundle
|
||||
import com.intellij.openapi.vcs.VcsConfiguration
|
||||
import com.intellij.openapi.vcs.VcsException
|
||||
import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.ui.ColoredTreeCellRenderer
|
||||
import com.intellij.ui.DoubleClickListener
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.ui.TableSpeedSearch
|
||||
import com.intellij.ui.layout.*
|
||||
import com.intellij.ui.speedSearch.SpeedSearchUtil
|
||||
import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns
|
||||
import com.intellij.ui.treeStructure.treetable.TreeTable
|
||||
import com.intellij.ui.treeStructure.treetable.TreeTableModel
|
||||
import com.intellij.util.containers.Convertor
|
||||
import com.intellij.util.ui.ColumnInfo
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import com.intellij.util.ui.tree.TreeUtil
|
||||
import org.jetbrains.annotations.NonNls
|
||||
import java.awt.event.ActionEvent
|
||||
import java.awt.event.MouseEvent
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import javax.swing.*
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
open class MultipleFileMergeDialog2(
|
||||
private val project: Project?,
|
||||
files: List<VirtualFile>,
|
||||
private val mergeProvider: MergeProvider,
|
||||
private val mergeDialogCustomizer: MergeDialogCustomizer
|
||||
) : DialogWrapper(project) {
|
||||
|
||||
private var files = files.toMutableList()
|
||||
private val mergeSession = (mergeProvider as? MergeProvider2)?.createMergeSession(files)
|
||||
val processedFiles = mutableListOf<VirtualFile>()
|
||||
private lateinit var table: TreeTable
|
||||
private lateinit var acceptYoursButton: JButton
|
||||
private lateinit var acceptTheirsButton: JButton
|
||||
private lateinit var mergeButton: JButton
|
||||
private val tableModel = ListTreeTableModelOnColumns(DefaultMutableTreeNode(), createColumns())
|
||||
private val binaryFiles = files.filter { it.fileType.isBinary || mergeProvider.isBinary(it) }
|
||||
private val projectManager = ProjectManagerEx.getInstanceEx()
|
||||
private var groupByDirectory = project?.let { VcsConfiguration.getInstance(it).GROUP_MULTIFILE_MERGE_BY_DIRECTORY } ?: false
|
||||
|
||||
private val virtualFileRenderer = object : ColoredTreeCellRenderer() {
|
||||
override fun customizeCellRenderer(tree: JTree,
|
||||
value: Any?,
|
||||
selected: Boolean,
|
||||
expanded: Boolean,
|
||||
leaf: Boolean,
|
||||
row: Int,
|
||||
hasFocus: Boolean) {
|
||||
val data = (value as DefaultMutableTreeNode).userObject
|
||||
when (data) {
|
||||
is String -> {
|
||||
icon = AllIcons.Nodes.Folder
|
||||
val parent = value.parent as DefaultMutableTreeNode
|
||||
val parentPath = parent.userObject as String?
|
||||
append(if (parentPath == null) FileUtil.getLocationRelativeToUserHome(data) else data.substring(parentPath.length + 1))
|
||||
}
|
||||
|
||||
is VirtualFile -> {
|
||||
icon = VirtualFilePresentation.getIcon(data)
|
||||
append(data.name, SimpleTextAttributes.REGULAR_ATTRIBUTES)
|
||||
if (data in binaryFiles) {
|
||||
append(" [${VcsBundle.message("multiple.file.merge.type.binary")}]", SimpleTextAttributes.REGULAR_ATTRIBUTES)
|
||||
}
|
||||
if (!groupByDirectory) {
|
||||
val parent = data.parent
|
||||
if (parent != null) {
|
||||
append(" (" + FileUtil.getLocationRelativeToUserHome(FileUtil.toSystemDependentName(parent.presentableUrl)) + ")", SimpleTextAttributes.GRAYED_ATTRIBUTES)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SpeedSearchUtil.applySpeedSearchHighlighting(this@MultipleFileMergeDialog2.table, this, true, selected)
|
||||
}
|
||||
|
||||
override fun calcFocusedState() = table.hasFocus()
|
||||
}
|
||||
|
||||
init {
|
||||
projectManager.blockReloadingProjectOnExternalChanges()
|
||||
title = mergeDialogCustomizer.multipleFileDialogTitle
|
||||
virtualFileRenderer.font = UIUtil.getListFont()
|
||||
|
||||
@Suppress("LeakingThis")
|
||||
init()
|
||||
|
||||
updateColumnSizes()
|
||||
updateTree()
|
||||
table.tree.selectionModel.addTreeSelectionListener { updateButtonState() }
|
||||
table.selectionModel.setSelectionInterval(0, 0)
|
||||
object : DoubleClickListener() {
|
||||
override fun onDoubleClick(event: MouseEvent): Boolean {
|
||||
showMergeDialog()
|
||||
return true
|
||||
}
|
||||
}.installOn(table)
|
||||
|
||||
TableSpeedSearch(table, Convertor { (it as? VirtualFile)?.name })
|
||||
}
|
||||
|
||||
override fun createCenterPanel(): JComponent {
|
||||
return panel {
|
||||
val description = mergeDialogCustomizer.getMultipleFileMergeDescription(processedFiles)
|
||||
if (!description.isNullOrBlank()) {
|
||||
row {
|
||||
label(description!!)
|
||||
}
|
||||
}
|
||||
|
||||
row {
|
||||
ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, createToolbarActionGroup(), true).component()
|
||||
}
|
||||
|
||||
row {
|
||||
scrollPane(TreeTable(tableModel).also {
|
||||
table = it
|
||||
it.tree.isRootVisible = false
|
||||
it.setTreeCellRenderer(virtualFileRenderer)
|
||||
if (tableModel.columnCount > 1) {
|
||||
it.setShowColumns(true)
|
||||
}
|
||||
it.rowHeight = virtualFileRenderer.preferredSize.height
|
||||
}, growX, growY, pushX, pushY)
|
||||
|
||||
cell(isVerticalFlow = true) {
|
||||
JButton("Accept Yours").also {
|
||||
it.addActionListener { acceptRevision(MergeSession.Resolution.AcceptedYours) }
|
||||
acceptYoursButton = it
|
||||
}()
|
||||
JButton("Accept Theirs").also {
|
||||
it.addActionListener { acceptRevision(MergeSession.Resolution.AcceptedTheirs) }
|
||||
acceptTheirsButton = it
|
||||
}()
|
||||
val mergeAction = object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) {
|
||||
showMergeDialog()
|
||||
}
|
||||
}
|
||||
mergeAction.putValue(DialogWrapper.DEFAULT_ACTION, java.lang.Boolean.TRUE)
|
||||
createJButtonForAction(mergeAction).also {
|
||||
it.text = "Merge..."
|
||||
mergeButton = it
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createColumns(): Array<ColumnInfo<*, *>> {
|
||||
val columns = ArrayList<ColumnInfo<*, *>>()
|
||||
columns.add(object : ColumnInfo<DefaultMutableTreeNode, Any>(VcsBundle.message("multiple.file.merge.column.name")) {
|
||||
override fun valueOf(node: DefaultMutableTreeNode) = node.userObject
|
||||
override fun getColumnClass(): Class<*> = TreeTableModel::class.java
|
||||
})
|
||||
|
||||
mergeSession?.mergeInfoColumns?.mapTo(columns) { ColumnInfoAdapter(it) }
|
||||
return columns.toTypedArray()
|
||||
}
|
||||
|
||||
private class ColumnInfoAdapter(private val base: ColumnInfo<Any, Any>) : ColumnInfo<DefaultMutableTreeNode, Any>(base.name) {
|
||||
override fun valueOf(node: DefaultMutableTreeNode) = (node.userObject as? VirtualFile)?.let { base.valueOf(it) }
|
||||
override fun getMaxStringValue() = base.maxStringValue
|
||||
override fun getAdditionalWidth() = base.additionalWidth
|
||||
}
|
||||
|
||||
private fun updateColumnSizes() {
|
||||
for ((index, columnInfo) in tableModel.columns.withIndex()) {
|
||||
val column = table.columnModel.getColumn(index)
|
||||
columnInfo.maxStringValue?.let {
|
||||
column.maxWidth = table.getFontMetrics(table.font).stringWidth(it) + columnInfo.additionalWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createToolbarActionGroup() = DefaultActionGroup().apply {
|
||||
add(object : ToggleAction("Group by Directory", "Group by Directory", AllIcons.Actions.GroupByPackage) {
|
||||
override fun isSelected(e: AnActionEvent?) = groupByDirectory
|
||||
|
||||
override fun setSelected(e: AnActionEvent?, state: Boolean) {
|
||||
groupByDirectory = state
|
||||
project?.let { VcsConfiguration.getInstance(it).GROUP_MULTIFILE_MERGE_BY_DIRECTORY = groupByDirectory }
|
||||
updateTree()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateTree() {
|
||||
val root = DefaultMutableTreeNode()
|
||||
tableModel.setRoot(root)
|
||||
val commonAncestor = if (groupByDirectory) VfsUtil.getCommonAncestor(files) else null
|
||||
if (commonAncestor != null) {
|
||||
buildGroupedFileTree(root, commonAncestor)
|
||||
}
|
||||
else {
|
||||
for (file in files) {
|
||||
tableModel.insertNodeInto(DefaultMutableTreeNode(file, false), root, root.childCount)
|
||||
}
|
||||
}
|
||||
TreeUtil.expandAll(table.tree)
|
||||
}
|
||||
|
||||
private fun buildGroupedFileTree(root: DefaultMutableTreeNode, commonAncestor: VirtualFile) {
|
||||
val directoryNodes = mutableMapOf<String, DefaultMutableTreeNode>()
|
||||
val commonAncestorNode = DefaultMutableTreeNode(commonAncestor.path)
|
||||
directoryNodes[commonAncestor.path] = commonAncestorNode
|
||||
tableModel.insertNodeInto(commonAncestorNode, root, 0)
|
||||
|
||||
for (file in files) {
|
||||
var currentParentNode = commonAncestorNode
|
||||
var index = commonAncestor.path.length
|
||||
val lastIndex = file.path.lastIndexOf('/')
|
||||
while (index < lastIndex) {
|
||||
val nextIndex = file.path.indexOf('/', index)
|
||||
val path = file.path.substring(0, nextIndex)
|
||||
val directoryNode = directoryNodes.getOrPut(path) {
|
||||
DefaultMutableTreeNode(path).also {
|
||||
TreeUtil.insertNode(it, currentParentNode, tableModel, compareBy { it.userObject as String })
|
||||
}
|
||||
}
|
||||
index = nextIndex + 1
|
||||
currentParentNode = directoryNode
|
||||
}
|
||||
|
||||
TreeUtil.insertNode(
|
||||
DefaultMutableTreeNode(file, false), currentParentNode, tableModel,
|
||||
compareBy { (it.userObject as VirtualFile).path }
|
||||
)
|
||||
}
|
||||
|
||||
collapseMiddlePaths(commonAncestorNode)
|
||||
}
|
||||
|
||||
private fun collapseMiddlePaths(node: DefaultMutableTreeNode) {
|
||||
if (node.childCount == 1) {
|
||||
val child = node.firstChild as DefaultMutableTreeNode
|
||||
if (child.userObject is String) {
|
||||
val parent = node.parent as DefaultMutableTreeNode
|
||||
tableModel.removeNodeFromParent(node)
|
||||
TreeUtil.insertNode(child, parent, tableModel, compareBy { it.userObject as String })
|
||||
collapseMiddlePaths(child)
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (child in node.children()) {
|
||||
collapseMiddlePaths(child as DefaultMutableTreeNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateButtonState() {
|
||||
val selectedFiles = getSelectedFiles()
|
||||
val haveSelection = selectedFiles.any()
|
||||
val haveUnmergeableFiles = selectedFiles.any { mergeSession?.canMerge(it) == false }
|
||||
|
||||
acceptYoursButton.isEnabled = haveSelection
|
||||
acceptTheirsButton.isEnabled = haveSelection
|
||||
mergeButton.isEnabled = haveSelection && !haveUnmergeableFiles
|
||||
}
|
||||
|
||||
|
||||
private fun getSelectedFiles(): List<VirtualFile> {
|
||||
return TreeUtil.collectSelectedObjectsOfType(table.tree, VirtualFile::class.java)
|
||||
}
|
||||
|
||||
protected fun beforeResolve(files: Collection<VirtualFile>): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun createActions() = arrayOf(cancelAction)
|
||||
|
||||
|
||||
override fun getCancelAction(): Action = super.getCancelAction().apply {
|
||||
putValue(Action.NAME, CommonBundle.getCloseButtonText())
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
projectManager.unblockReloadingProjectOnExternalChanges()
|
||||
super.dispose()
|
||||
}
|
||||
|
||||
@NonNls
|
||||
override fun getDimensionServiceKey() = "MultipleFileMergeDialog"
|
||||
|
||||
private fun acceptRevision(resolution: MergeSession.Resolution) {
|
||||
FileDocumentManager.getInstance().saveAllDocuments()
|
||||
val files = getSelectedFiles()
|
||||
if (!beforeResolve(files)) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
for (file in files) {
|
||||
acceptFileRevision(file, resolution)
|
||||
checkMarkModifiedProject(file)
|
||||
markFileProcessed(file, resolution)
|
||||
}
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn(e)
|
||||
Messages.showErrorDialog(contentPanel, "Error saving merged data: " + e.message)
|
||||
}
|
||||
|
||||
updateModelFromFiles()
|
||||
}
|
||||
|
||||
private fun acceptFileRevision(file: VirtualFile, resolution: MergeSession.Resolution) {
|
||||
if (mergeSession?.canMerge(file) == false) return
|
||||
|
||||
if (mergeSession?.acceptFileRevision(file, resolution) == true) return
|
||||
|
||||
if (!DiffUtil.makeWritable(project, file)) {
|
||||
throw IOException("File is read-only: " + file.presentableName)
|
||||
}
|
||||
|
||||
val isCurrent = resolution == MergeSession.Resolution.AcceptedYours
|
||||
val data = mergeProvider.loadRevisions(file)
|
||||
|
||||
writeCommandAction(project).withName("Accept " + if (isCurrent) "Yours" else "Theirs").run<Exception> {
|
||||
if (isCurrent) {
|
||||
file.setBinaryContent(data.CURRENT)
|
||||
}
|
||||
else {
|
||||
file.setBinaryContent(data.LAST)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun markFileProcessed(file: VirtualFile, resolution: MergeSession.Resolution) {
|
||||
files.remove(file)
|
||||
if (mergeSession != null) {
|
||||
mergeSession.conflictResolvedForFile(file, resolution)
|
||||
}
|
||||
else {
|
||||
mergeProvider.conflictResolvedForFile(file)
|
||||
}
|
||||
processedFiles.add(file)
|
||||
project?.let { VcsDirtyScopeManager.getInstance(it).fileDirty(file) }
|
||||
}
|
||||
|
||||
private fun updateModelFromFiles() {
|
||||
if (files.isEmpty()) {
|
||||
doCancelAction()
|
||||
}
|
||||
else {
|
||||
var selIndex = table.selectionModel.minSelectionIndex
|
||||
updateTree()
|
||||
if (selIndex >= files.size) {
|
||||
selIndex = files.size - 1
|
||||
}
|
||||
table.selectionModel.setSelectionInterval(selIndex, selIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMergeDialog() {
|
||||
val requestFactory = DiffRequestFactory.getInstance()
|
||||
val files = getSelectedFiles()
|
||||
if (files.isEmpty()) return
|
||||
if (!beforeResolve(files)) {
|
||||
return
|
||||
}
|
||||
|
||||
for (file in files) {
|
||||
val mergeData: MergeData
|
||||
try {
|
||||
mergeData = mergeProvider.loadRevisions(file)
|
||||
}
|
||||
catch (ex: VcsException) {
|
||||
Messages.showErrorDialog(contentPanel, "Error loading revisions to merge: " + ex.message)
|
||||
break
|
||||
}
|
||||
|
||||
if (mergeData.CURRENT == null || mergeData.LAST == null || mergeData.ORIGINAL == null) {
|
||||
Messages.showErrorDialog(contentPanel, "Error loading revisions to merge")
|
||||
break
|
||||
}
|
||||
|
||||
val leftTitle = mergeDialogCustomizer.getLeftPanelTitle(file)
|
||||
val baseTitle = mergeDialogCustomizer.getCenterPanelTitle(file)
|
||||
val rightTitle = mergeDialogCustomizer.getRightPanelTitle(file, mergeData.LAST_REVISION_NUMBER)
|
||||
val title = mergeDialogCustomizer.getMergeWindowTitle(file)
|
||||
|
||||
val byteContents = listOf(mergeData.CURRENT, mergeData.ORIGINAL, mergeData.LAST)
|
||||
val contentTitles = listOf(leftTitle, baseTitle, rightTitle)
|
||||
|
||||
val callback = { result: MergeResult ->
|
||||
val document = FileDocumentManager.getInstance().getCachedDocument(file)
|
||||
if (document != null) FileDocumentManager.getInstance().saveDocument(document)
|
||||
checkMarkModifiedProject(file)
|
||||
|
||||
if (result != MergeResult.CANCEL) {
|
||||
markFileProcessed(file, getSessionResolution(result))
|
||||
}
|
||||
}
|
||||
|
||||
val request: MergeRequest
|
||||
try {
|
||||
if (mergeProvider.isBinary(file)) { // respect MIME-types in svn
|
||||
request = requestFactory.createBinaryMergeRequest(project, file, byteContents, title, contentTitles, callback)
|
||||
}
|
||||
else {
|
||||
request = requestFactory.createMergeRequest(project, file, byteContents, title, contentTitles, callback)
|
||||
}
|
||||
|
||||
MergeUtil.putRevisionInfos(request, mergeData)
|
||||
}
|
||||
catch (e: InvalidDiffRequestException) {
|
||||
LOG.error(e)
|
||||
Messages.showErrorDialog(contentPanel, "Can't show merge dialog")
|
||||
break
|
||||
}
|
||||
|
||||
DiffManager.getInstance().showMerge(project, request)
|
||||
}
|
||||
updateModelFromFiles()
|
||||
}
|
||||
|
||||
private fun getSessionResolution(result: MergeResult): MergeSession.Resolution = when (result) {
|
||||
MergeResult.LEFT -> MergeSession.Resolution.AcceptedYours
|
||||
MergeResult.RIGHT -> MergeSession.Resolution.AcceptedTheirs
|
||||
MergeResult.RESOLVED -> MergeSession.Resolution.Merged
|
||||
else -> throw IllegalArgumentException(result.name)
|
||||
}
|
||||
|
||||
private fun checkMarkModifiedProject(file: VirtualFile) {
|
||||
MergeVersion.MergeDocumentVersion.reportProjectFileChangeIfNeeded(project, file)
|
||||
}
|
||||
|
||||
override fun getPreferredFocusedComponent(): JComponent? = table
|
||||
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(MultipleFileMergeDialog2::class.java)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user