mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[git-index] add a commit message panel
GitOrigin-RevId: b8cc6b50a4c0634ec0d4630f79a48d0cda382272
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a6f2c944cd
commit
8ab3f0e225
@@ -16,6 +16,7 @@ vcs.revision.name.current=Current
|
||||
message.text.could.not.load.file.content=Could Not Load File Content
|
||||
confirmation.text.check.in.with.empty.comment=Commit with empty comment?
|
||||
confirmation.title.check.in.with.empty.comment=Comment Is Empty
|
||||
commit.message.placeholder=Commit Message
|
||||
label.commit.comment=&Commit Message
|
||||
border.standard.checkin.options.group=Before {0}
|
||||
border.standard.after.checkin.options.group=After {0}
|
||||
|
||||
@@ -64,7 +64,13 @@ private val MAC_COMMIT_ACTION_SHORTCUT = CustomShortcutSet(getKeyStroke(KeyEvent
|
||||
|
||||
private fun panel(layout: LayoutManager): JBPanel<*> = JBPanel<JBPanel<*>>(layout)
|
||||
|
||||
private fun JBOptionButton.getBottomInset(): Int =
|
||||
fun showEmptyCommitMessageConfirmation() = Messages.YES == Messages.showYesNoDialog(
|
||||
message("confirmation.text.check.in.with.empty.comment"),
|
||||
message("confirmation.title.check.in.with.empty.comment"),
|
||||
Messages.getWarningIcon()
|
||||
)
|
||||
|
||||
fun JBOptionButton.getBottomInset(): Int =
|
||||
border?.getBorderInsets(this)?.bottom
|
||||
?: (components.firstOrNull() as? JComponent)?.insets?.bottom
|
||||
?: 0
|
||||
@@ -118,7 +124,7 @@ open class ChangesViewCommitPanel(private val changesView: ChangesListView, priv
|
||||
|
||||
private val commitMessage = CommitMessage(project, false, false, true).apply {
|
||||
editorField.addSettingsProvider { it.setBorder(emptyLeft(6)) }
|
||||
editorField.setPlaceholder("Commit Message")
|
||||
editorField.setPlaceholder(message("commit.message.placeholder"))
|
||||
}
|
||||
private val defaultCommitAction = object : AbstractAction() {
|
||||
override fun actionPerformed(e: ActionEvent) = fireDefaultExecutorCalled()
|
||||
@@ -383,12 +389,7 @@ open class ChangesViewCommitPanel(private val changesView: ChangesListView, priv
|
||||
override fun addInclusionListener(listener: InclusionListener, parent: Disposable) =
|
||||
inclusionEventDispatcher.addListener(listener, parent)
|
||||
|
||||
override fun confirmCommitWithEmptyMessage(): Boolean =
|
||||
Messages.YES == Messages.showYesNoDialog(
|
||||
message("confirmation.text.check.in.with.empty.comment"),
|
||||
message("confirmation.title.check.in.with.empty.comment"),
|
||||
Messages.getWarningIcon()
|
||||
)
|
||||
override fun confirmCommitWithEmptyMessage(): Boolean = showEmptyCommitMessageConfirmation()
|
||||
|
||||
override fun startBeforeCommitChecks() = Unit
|
||||
override fun endBeforeCommitChecks(result: CheckinHandler.ReturnResult) = Unit
|
||||
|
||||
@@ -563,6 +563,7 @@ stage.tree.node.unstaged=Not staged for commit
|
||||
stage.tree.node.unmerged=Unmerged
|
||||
stage.tree.node.untracked=Untracked
|
||||
stage.tree.node.ignored=Ignored
|
||||
stage.commit.process=Committing Staged Changes...
|
||||
stage.loading.status=Loading changes...
|
||||
|
||||
branches.selected.branches.updated.title=Selected {0,choice,1#branch|2#branches} Updated
|
||||
|
||||
@@ -979,8 +979,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment, AmendCommitAwa
|
||||
return file;
|
||||
}
|
||||
|
||||
private static void runWithMessageFile(@NotNull Project project, @NotNull VirtualFile root, @NotNull String message,
|
||||
@NotNull ThrowableConsumer<? super File, ? extends VcsException> task) throws VcsException {
|
||||
public static void runWithMessageFile(@NotNull Project project, @NotNull VirtualFile root, @NotNull String message,
|
||||
@NotNull ThrowableConsumer<? super File, ? extends VcsException> task) throws VcsException {
|
||||
File messageFile;
|
||||
try {
|
||||
messageFile = createCommitMessageFile(project, root, message);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2000-2020 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 git4idea.index
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import com.intellij.openapi.progress.Task.Backgroundable
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vcs.VcsException
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import git4idea.checkin.GitCheckinEnvironment
|
||||
import git4idea.commands.Git
|
||||
import git4idea.commands.GitCommand
|
||||
import git4idea.commands.GitLineHandler
|
||||
import git4idea.i18n.GitBundle
|
||||
import git4idea.repo.GitRepositoryManager
|
||||
import java.io.File
|
||||
|
||||
private val LOG = Logger.getInstance("#git4idea.index.GitCommitUtil")
|
||||
|
||||
fun performCommit(project: Project, roots: Collection<VirtualFile>, commitMessage: String, amend: Boolean = false) {
|
||||
object : Backgroundable(project, GitBundle.message("stage.commit.process")) {
|
||||
override fun run(indicator: ProgressIndicator) {
|
||||
for (root in roots) {
|
||||
try {
|
||||
GitCheckinEnvironment.runWithMessageFile(project, root, commitMessage) { commitMessageFile: File ->
|
||||
doCommit(project, root, commitMessageFile, amend)
|
||||
}
|
||||
GitRepositoryManager.getInstance(project).getRepositoryForRoot(root)?.repositoryFiles?.refresh()
|
||||
}
|
||||
catch (e: VcsException) {
|
||||
LOG.error("Error while committing $root", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.queue()
|
||||
}
|
||||
|
||||
@Throws(VcsException::class)
|
||||
private fun doCommit(project: Project, root: VirtualFile, commitMessageFile: File, amend: Boolean) {
|
||||
val handler = GitLineHandler(project, root, GitCommand.COMMIT)
|
||||
handler.setStdoutSuppressed(false)
|
||||
handler.addParameters("-F")
|
||||
handler.addAbsoluteFile(commitMessageFile)
|
||||
if (amend) {
|
||||
handler.addParameters("--amend")
|
||||
}
|
||||
handler.endOptions()
|
||||
Git.getInstance().runCommand(handler).getOutputOrThrow()
|
||||
}
|
||||
@@ -99,6 +99,16 @@ class GitStageTracker(val project: Project) : Disposable {
|
||||
data class State(val gitState: Map<VirtualFile, List<GitFileStatus>>) {
|
||||
private val roots: Collection<VirtualFile>
|
||||
get() = gitState.keys
|
||||
val stagedRoots: Set<VirtualFile>
|
||||
get() {
|
||||
return gitState.filterValues {
|
||||
it.any { line -> line.getStagedStatus() != null }
|
||||
}.keys
|
||||
}
|
||||
|
||||
fun hasStagedRoots(): Boolean {
|
||||
return gitState.values.flatten().any { it.getStagedStatus() != null }
|
||||
}
|
||||
|
||||
fun updatedWith(newState: State, roots: Collection<VirtualFile> = this.roots.union(newState.roots)): State {
|
||||
val gitState = hashMapOf<VirtualFile, List<GitFileStatus>>()
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2000-2020 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 git4idea.index.ui
|
||||
|
||||
import com.intellij.idea.ActionsBundle
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.actionSystem.ex.CheckboxAction
|
||||
import com.intellij.openapi.editor.colors.EditorColorsListener
|
||||
import com.intellij.openapi.editor.colors.EditorColorsScheme
|
||||
import com.intellij.openapi.editor.ex.EditorEx
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.ComponentContainer
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.VcsBundle
|
||||
import com.intellij.openapi.vcs.ui.CommitMessage
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.components.JBOptionButton
|
||||
import com.intellij.ui.components.JBPanel
|
||||
import com.intellij.ui.components.panels.HorizontalLayout
|
||||
import com.intellij.util.ui.JBUI
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel
|
||||
import com.intellij.vcs.commit.getBottomInset
|
||||
import git4idea.i18n.GitBundle
|
||||
import java.awt.Component
|
||||
import java.awt.event.ActionEvent
|
||||
import javax.swing.AbstractAction
|
||||
import javax.swing.JButton
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.SwingConstants
|
||||
import javax.swing.border.Border
|
||||
import javax.swing.border.EmptyBorder
|
||||
|
||||
abstract class GitCommitPanel(project: Project,
|
||||
parent: Disposable) : BorderLayoutPanel(), EditorColorsListener, ComponentContainer, DataProvider {
|
||||
var isAmend: Boolean = false
|
||||
|
||||
val commitMessage = CommitMessage(project, false, false, true)
|
||||
val commitButton = CommitButton()
|
||||
|
||||
init {
|
||||
addToCenter(buildPanel())
|
||||
withPreferredHeight(85)
|
||||
|
||||
Disposer.register(this, commitMessage)
|
||||
Disposer.register(parent, this)
|
||||
}
|
||||
|
||||
private fun buildPanel(): Component {
|
||||
val centerPanel = JBUI.Panels.simplePanel()
|
||||
|
||||
val amendActionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN,
|
||||
DefaultActionGroup(AmendAction()), true)
|
||||
amendActionToolbar.setTargetComponent(this)
|
||||
amendActionToolbar.setReservePlaceAutoPopupIcon(false)
|
||||
amendActionToolbar.component.isOpaque = false
|
||||
amendActionToolbar.component.border = null
|
||||
amendActionToolbar.component.background = getButtonPanelBackground()
|
||||
|
||||
val bottomPanel = JBPanel<JBPanel<*>>(HorizontalLayout(JBUI.scale(4), SwingConstants.CENTER))
|
||||
bottomPanel.background = getButtonPanelBackground()
|
||||
bottomPanel.border = getButtonPanelBorder()
|
||||
bottomPanel.add(commitButton)
|
||||
bottomPanel.add(amendActionToolbar.component)
|
||||
|
||||
commitMessage.editorField.addSettingsProvider { it.setBorder(JBUI.Borders.emptyLeft(6)) }
|
||||
commitMessage.editorField.setPlaceholder(VcsBundle.message("commit.message.placeholder"))
|
||||
|
||||
centerPanel.addToCenter(commitMessage).addToBottom(bottomPanel)
|
||||
return centerPanel
|
||||
}
|
||||
|
||||
protected abstract fun performCommit()
|
||||
|
||||
protected abstract fun isFocused(): Boolean
|
||||
|
||||
private fun getButtonPanelBorder(): Border =
|
||||
EmptyBorder(0, JBUI.scale(4), 0, 0)
|
||||
|
||||
private fun getButtonPanelBackground() =
|
||||
JBColor { (commitMessage.editorField.editor as? EditorEx)?.backgroundColor ?: UIUtil.getTreeBackground() }
|
||||
|
||||
override fun globalSchemeChange(scheme: EditorColorsScheme?) {
|
||||
// todo
|
||||
}
|
||||
|
||||
override fun getComponent(): JComponent = this
|
||||
|
||||
override fun getPreferredFocusableComponent(): JComponent = commitMessage.editorField
|
||||
|
||||
override fun getData(dataId: String) = commitMessage.getData(dataId)
|
||||
|
||||
override fun dispose() {
|
||||
}
|
||||
|
||||
private fun getCommitText(): String {
|
||||
if (isAmend) return ActionsBundle.message("action.Vcs.ToggleAmendCommitMode.text")
|
||||
else return GitBundle.getString("commit.action.name")
|
||||
}
|
||||
|
||||
inner class CommitButton : JButton(object : AbstractAction(getCommitText()) {
|
||||
override fun actionPerformed(e: ActionEvent) {
|
||||
performCommit()
|
||||
}
|
||||
}) {
|
||||
|
||||
init {
|
||||
background = getButtonPanelBackground()
|
||||
}
|
||||
|
||||
override fun isDefaultButton(): Boolean = isFocused()
|
||||
}
|
||||
|
||||
inner class AmendAction : CheckboxAction(VcsBundle.messagePointer("checkbox.amend")) {
|
||||
override fun isSelected(e: AnActionEvent): Boolean = isAmend
|
||||
override fun setSelected(e: AnActionEvent, state: Boolean) {
|
||||
isAmend = state
|
||||
commitButton.text = getCommitText()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,11 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangesTree
|
||||
import com.intellij.openapi.vcs.changes.ui.TreeActionsToolbarPanel
|
||||
import com.intellij.openapi.wm.IdeFocusManager
|
||||
import com.intellij.ui.OnePixelSplitter
|
||||
import com.intellij.ui.ScrollPaneFactory
|
||||
import com.intellij.ui.SideBorder
|
||||
import com.intellij.vcs.commit.showEmptyCommitMessageConfirmation
|
||||
import com.intellij.vcs.log.ui.frame.ProgressStripe
|
||||
import git4idea.i18n.GitBundle
|
||||
import git4idea.index.GitStageTracker
|
||||
@@ -24,6 +27,7 @@ internal class GitStagePanel(private val tracker: GitStageTracker, disposablePar
|
||||
private val project = tracker.project
|
||||
|
||||
private val tree: GitStageTree
|
||||
private val commitPanel: GitCommitPanel
|
||||
private val progressStripe: ProgressStripe
|
||||
|
||||
private val state: GitStageTracker.State
|
||||
@@ -31,6 +35,7 @@ internal class GitStagePanel(private val tracker: GitStageTracker, disposablePar
|
||||
|
||||
init {
|
||||
tree = MyChangesTree(project)
|
||||
commitPanel = MyGitCommitPanel()
|
||||
|
||||
val toolbarGroup = DefaultActionGroup()
|
||||
toolbarGroup.add(ActionManager.getInstance().getAction("Git.Stage.Toolbar"))
|
||||
@@ -43,8 +48,12 @@ internal class GitStagePanel(private val tracker: GitStageTracker, disposablePar
|
||||
|
||||
val scrolledTree = ScrollPaneFactory.createScrollPane(tree, SideBorder.TOP)
|
||||
progressStripe = ProgressStripe(scrolledTree, this, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS)
|
||||
val treeMessageSplitter = OnePixelSplitter(true, "git.stage.tree.message.splitter", 0.7f)
|
||||
treeMessageSplitter.firstComponent = progressStripe
|
||||
treeMessageSplitter.secondComponent = commitPanel
|
||||
|
||||
add(toolbar.component, BorderLayout.NORTH)
|
||||
add(progressStripe, BorderLayout.CENTER)
|
||||
add(treeMessageSplitter, BorderLayout.CENTER)
|
||||
|
||||
tracker.addListener(MyGitStageTrackerListener(), this)
|
||||
if (tracker.isRefreshInProgress) {
|
||||
@@ -56,8 +65,18 @@ internal class GitStagePanel(private val tracker: GitStageTracker, disposablePar
|
||||
Disposer.register(disposableParent, this)
|
||||
}
|
||||
|
||||
private fun performCommit(amend: Boolean) {
|
||||
val rootsToCommit = state.stagedRoots
|
||||
if (rootsToCommit.isEmpty()) return
|
||||
|
||||
if (commitPanel.commitMessage.text.isBlank() && !showEmptyCommitMessageConfirmation()) return
|
||||
|
||||
git4idea.index.performCommit(project, rootsToCommit, commitPanel.commitMessage.text, amend)
|
||||
}
|
||||
|
||||
fun update() {
|
||||
tree.update()
|
||||
commitPanel.commitButton.isEnabled = state.hasStagedRoots()
|
||||
}
|
||||
|
||||
override fun getData(dataId: String): Any? {
|
||||
@@ -73,6 +92,16 @@ internal class GitStagePanel(private val tracker: GitStageTracker, disposablePar
|
||||
get() = this@GitStagePanel.state
|
||||
}
|
||||
|
||||
inner class MyGitCommitPanel : GitCommitPanel(project, this) {
|
||||
override fun isFocused(): Boolean {
|
||||
return IdeFocusManager.getInstance(project).getFocusedDescendantFor(this@GitStagePanel) != null
|
||||
}
|
||||
|
||||
override fun performCommit() {
|
||||
performCommit(isAmend)
|
||||
}
|
||||
}
|
||||
|
||||
inner class MyGitStageTrackerListener : GitStageTrackerListener {
|
||||
override fun update() {
|
||||
this@GitStagePanel.update()
|
||||
|
||||
@@ -352,6 +352,15 @@ public class GitRepositoryFiles {
|
||||
return path.equals(myExcludePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh all .git repository files asynchronously and recursively.
|
||||
*
|
||||
* @see #refreshTagsFiles() if you need the "main" data (branches, HEAD, etc.) to be updated synchronously.
|
||||
*/
|
||||
public void refresh() {
|
||||
VfsUtil.markDirtyAndRefresh(true, true, false, myMainDir, myWorktreeDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh that part of .git repository files, which is not covered by {@link GitRepository#update()}, e.g. the {@code refs/tags/} dir.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user