and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.commit;
+
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Provides access to the context of a commit in progress: which repository, and
+ * the commit message.
+ *
+ * This can be used by custom commands contributed via plugin.xml to the
+ * {@link #COMMIT_MSG_TOOLBAR_ID} to access and modify the commit message.
+ *
+ *
+ * In plugin.xml, define a command, handler, and menu contribution
+ * to the toolbar:
+ *
+ *
+ * <extension point="org.eclipse.ui.commands">
+ * <command
+ * categoryId="my.commandCategory"
+ * id="my.CommandId"
+ * name="My Command" />
+ * </extension>
+ * <extension point="org.eclipse.ui.commandImages">
+ * <image commandId="my.CommandId" icon="some icon path" />
+ * </extension>
+ * <extension point="org.eclipse.ui.handlers">
+ * <handler commandId="my.commandId">
+ * <class class="my.package.MyCommandHandler" />
+ * </handler>
+ * </extension>
+ * <extension point="org.eclipse.ui.menus">
+ * <menuContribution
+ * locationURI="toolbar:org.eclipse.egit.ui.commitMsgToolBar?after=additions">
+ * <command
+ * commandId="my.CommandId"
+ * label="My Command"
+ * style="push" />
+ * </menuContribution>
+ * </extension>
+ *
+ *
+ * and implement your command handler:
+ *
+ *
+ * package my.package;
+ *
+ * import org.eclipse.core.commands.AbstractHandler;
+ * import org.eclipse.core.commands.ExecutionEvent;
+ * import org.eclipse.core.commands.ExecutionException;
+ * import org.eclipse.egit.ui.commit.CommitContext;
+ * import org.eclipse.egit.ui.commit.CommitContextUtils;
+ *
+ * public class MyCommandHandler extends AbstractHandler {
+ *
+ * public Object execute(ExecutionEvent event) throws ExecutionException {
+ * CommitContext context = CommitContextUtils.getCommitContext(event);
+ * if (context != null) {
+ * // Do something
+ * }
+ * return null;
+ * }
+ *
+ * }
+ *
+ *
+ * @since 7.4
+ */
+public interface CommitContext {
+
+ /**
+ * The ID of the commit message toolbar. This is the toolbar containing the
+ * "Amend", "Sign-Off", "Sign", and "Gerrit Change-Id" buttons. This ID can
+ * be used in plugin.xml to contribute additional commands to that toolbar,
+ * in both the staging view or in the commit dialog.
+ */
+ static final String COMMIT_MSG_TOOLBAR_ID = "org.eclipse.egit.ui.commitMsgToolBar"; //$NON-NLS-1$
+
+ /**
+ * Retrieves the {@link Repository} this {@link CommitContext} relates to.
+ * Use this to obtain additional information about the commit being made,
+ * such as staged/unstaged changes, or commit message settings like the
+ * clean-up mode or the comment character. (Note that the current comment
+ * character is also available directly via {@link #getCommentChar()} as a
+ * convenience.)
+ *
+ * @return the {@link Repository}; may be {@code null}.
+ */
+ Repository getRepository();
+
+ /**
+ * Retrieves the raw commit message text. The text uses plain LF as
+ * line delimiter and contains the raw message with no whitespace removed,
+ * no line-wrapping applied, and including all comment lines.
+ *
+ * @return the current commit message
+ */
+ String getCommitMessage();
+
+ /**
+ * Retrieves the current comment character used in the raw commit message.
+ *
+ * @return the comment character
+ */
+ char getCommentChar();
+
+ /**
+ * Sets the (raw) commit message.
+ *
+ * @param text
+ * the commit message to set
+ */
+ void setCommitMessage(String text);
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/commit/CommitContextUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/commit/CommitContextUtils.java
new file mode 100644
index 0000000000..b561c531b9
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/commit/CommitContextUtils.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (C) 2025, Thomas Wolf and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.commit;
+
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.runtime.Adapters;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * Utility operations on {@link CommitContext}s.
+ *
+ * @since 7.4
+ */
+public final class CommitContextUtils {
+
+ private CommitContextUtils() {
+ // No instantiation
+ }
+
+ /**
+ * Obtains the {@link CommitContext} from an {@link ExecutionEvent}. Useful
+ * in command handlers to get the context.
+ *
+ * @param event
+ * {@link ExecutionEvent} of the command invocation
+ * @return the {@link CommitContext}, or {@code null}Â if none is found
+ */
+ public static CommitContext getCommitContext(ExecutionEvent event) {
+ CommitContext context = null;
+ IWorkbenchPart part = HandlerUtil.getActivePart(event);
+ if (part != null) {
+ context = Adapters.adapt(part, CommitContext.class);
+ // If non-null now, we're in the staging view.
+ }
+ if (context == null) {
+ // In the commit dialog?
+ Shell shell = HandlerUtil.getActiveShell(event);
+ context = Adapters.adapt(
+ shell.getData(CommitContext.class.getCanonicalName()),
+ CommitContext.class);
+ }
+ return context;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java
index 4714a68e5a..d994d6e240 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIIcons.java
@@ -406,128 +406,128 @@ public class UIIcons {
static {
base = init();
- OVR_CHECKEDOUT = map("ovr/checkedout_ov.png"); //$NON-NLS-1$
- OVR_STAGED = map("ovr/staged.png"); //$NON-NLS-1$
- OVR_STAGED_ADD = map("ovr/staged_added.png"); //$NON-NLS-1$
- OVR_STAGED_REMOVE = map("ovr/staged_removed.png"); //$NON-NLS-1$
- OVR_STAGED_RENAME = map("ovr/staged_renamed.png"); //$NON-NLS-1$
- OVR_UNTRACKED = map("ovr/untracked.png"); //$NON-NLS-1$
- OVR_CONFLICT = map("ovr/conflict.png"); //$NON-NLS-1$
- OVR_DELETE_MODIFY = map("ovr/delete_modify.png"); //$NON-NLS-1$
- OVR_MODIFY_DELETE = map("ovr/modify_delete.png"); //$NON-NLS-1$
- OVR_ASSUMEUNCHANGED = map("ovr/assume_unchanged.png"); //$NON-NLS-1$
- OVR_DIRTY = map("ovr/dirty.png"); //$NON-NLS-1$
- OVR_SYMLINK = map("ovr/symlink_ovr.png"); //$NON-NLS-1$
- ELCL16_FIND = map("elcl16/find.png"); //$NON-NLS-1$
- ELCL16_COMPARE_VIEW = map("elcl16/compare_view.png"); //$NON-NLS-1$
- ELCL16_NEXT = map("elcl16/next_nav.png"); //$NON-NLS-1$
- ELCL16_PREVIOUS = map("elcl16/prev_nav.png"); //$NON-NLS-1$
- WIZBAN_CREATE_PATCH = map("wizban/createpatch_wizban.png"); //$NON-NLS-1$
- WIZBAN_IMPORT_REPO = map("wizban/import_wiz.png"); //$NON-NLS-1$
- WIZBAN_CONNECT_REPO = map("wizban/newconnect_wizban.png"); //$NON-NLS-1$
- WIZBAN_COMMIT = map("wizban/commit_wizban.png"); //$NON-NLS-1$
- WIZBAN_FETCH_GERRIT = map("wizban/fetch_gerrit_wizban.png"); //$NON-NLS-1$
- WIZBAN_FETCH = map("wizban/fetch_wizban.png"); //$NON-NLS-1$
- WIZBAN_PULL = map("wizban/pull_wizban.png"); //$NON-NLS-1$
- WIZBAN_PUSH_GERRIT = map("wizban/push_gerrit_wizban.png"); //$NON-NLS-1$
- WIZBAN_PUSH = map("wizban/push_wizban.png"); //$NON-NLS-1$
- WIZBAN_SYNCHRONIZE = map("wizban/synchronize_wizban.png"); //$NON-NLS-1$
- EDITCONFIG = map("obj16/editconfig.png"); //$NON-NLS-1$
- ELCL16_COMMIT = map("elcl16/commit.png"); //$NON-NLS-1$
- ELCL16_COMMENTS = map("elcl16/comment.png"); //$NON-NLS-1$
- ELCL16_AUTHOR = map("elcl16/author.png"); //$NON-NLS-1$
- ELCL16_COMMITTER = map("elcl16/committer.png"); //$NON-NLS-1$
- ELCL16_DELETE = map("elcl16/delete.png"); //$NON-NLS-1$
- ELCL16_ADD = map("elcl16/add.png"); //$NON-NLS-1$
- ELCL16_ADD_ALL = map("elcl16/add_all.png"); //$NON-NLS-1$
- ELCL16_TRASH = map("elcl16/trash_flat.png"); //$NON-NLS-1$
- ELCL16_CLEAR = map("elcl16/clear_co.png"); //$NON-NLS-1$
- ELCL16_REFRESH = map("elcl16/refresh.png"); //$NON-NLS-1$
- ELCL16_SYNCED = map("elcl16/synced.png"); //$NON-NLS-1$
- ELCL16_ID = map("elcl16/sha1.png"); //$NON-NLS-1$
- ELCL16_COLUMN_LAYOUT = map("elcl16/horizontal_view.png"); //$NON-NLS-1$
- ELCL16_FILTER = map("elcl16/filter_ps_funnel.png"); //$NON-NLS-1$
- ELCL16_PREVIEW = map("elcl16/preview.png"); //$NON-NLS-1$
- ELCL16_HIDE_UNTRACKED = map("elcl16/hide_untracked.png"); //$NON-NLS-1$
- FILTERNONE = map("elcl16/filter_none_funnel.png"); //$NON-NLS-1$
- FILTERRESOURCE = map("elcl16/filter_resource_funnel.png"); //$NON-NLS-1$
- FILTERPROJECT = map("elcl16/filter_project_funnel.png"); //$NON-NLS-1$
- FILTERFOLDER = map("elcl16/filter_folder_funnel.png"); //$NON-NLS-1$
- FETCH = map("obj16/fetch.png"); //$NON-NLS-1$
- PUSH = map("obj16/push.png"); //$NON-NLS-1$
- PULL = map("obj16/pull.png"); //$NON-NLS-1$
- REPOSITORY = map("obj16/repository_rep.png"); //$NON-NLS-1$
- REPOSITORY_GERRIT = map("obj16/repository_gerrit.png"); //$NON-NLS-1$
- NEW_REPOSITORY = map("etool16/newlocation_wiz.png"); //$NON-NLS-1$
- REMOTE_REPOSITORY = map("obj16/remote_entry_tbl.png"); //$NON-NLS-1$
- REMOTE_SPEC = map("obj16/synchronize.png"); //$NON-NLS-1$
- BRANCHES = map("obj16/branches_obj.png"); //$NON-NLS-1$
- TAGS = map("obj16/tags.png"); //$NON-NLS-1$
- TAG = map("obj16/version_rep.png"); //$NON-NLS-1$
- CREATE_TAG = map("obj16/new_tag_obj.png"); //$NON-NLS-1$
- BRANCH = map("obj16/branch_obj.png"); //$NON-NLS-1$
- CREATE_BRANCH = map("obj16/new_branch_obj.png"); //$NON-NLS-1$
- COLLAPSEALL = map("elcl16/collapseall.png"); //$NON-NLS-1$
- CLONEGIT = map("obj16/cloneGit.png"); //$NON-NLS-1$
- RESET = map("obj16/reset.png"); //$NON-NLS-1$
- CHANGESET = map("obj16/changelog_obj.png"); //$NON-NLS-1$
- GERRIT = map("obj16/gerrit_obj.png"); //$NON-NLS-1$
- EXPAND_ALL = map("elcl16/expandall.png"); //$NON-NLS-1$
- CHECKOUT = map("obj16/checkout.png"); //$NON-NLS-1$
- SIGNED_OFF = map("obj16/signed-off.png"); //$NON-NLS-1$
- CHECK_ALL = map("obj16/check_all.png"); //$NON-NLS-1$
- UNCHECK_ALL = map("obj16/uncheck_all.png"); //$NON-NLS-1$
- AMEND_COMMIT = map("obj16/commit_amend.png"); //$NON-NLS-1$
- UNTRACKED_FILE = map("obj16/untracked_file.png"); //$NON-NLS-1$
- NOTE = map("obj16/note.png"); //$NON-NLS-1$
- ANNOTATE = map("etool16/annotate.png"); //$NON-NLS-1$
- COMMIT = map("obj16/commit.png"); //$NON-NLS-1$
- CHERRY_PICK = map("obj16/cherry-pick.png"); //$NON-NLS-1$
- REBASE = map("obj16/rebase.png"); //$NON-NLS-1$
- REBASE_CONTINUE = map("elcl16/continue.png"); //$NON-NLS-1$
- REBASE_SKIP = map("elcl16/skip.png"); //$NON-NLS-1$
- REBASE_ABORT = map("elcl16/progress_stop.png"); //$NON-NLS-1$
- REBASE_PROCESS_STEPS = map("elcl16/start.png"); //$NON-NLS-1$
- OVR_ERROR = map("ovr/error.png"); //$NON-NLS-1$
- MERGE = map("obj16/merge.png"); //$NON-NLS-1$
- FIRST_PARENT_ONLY = map("obj16/first_parent_only.png"); //$NON-NLS-1$
- TAG_ANNOTATED = map("obj16/annotated-tag.png"); //$NON-NLS-1$
- CREATE_REPOSITORY = map("etool16/createRepository.png"); //$NON-NLS-1$
- SUBMODULES = map("obj16/submodules.png"); //$NON-NLS-1$
- CLEAN = map("obj16/clean_obj.png"); //$NON-NLS-1$
- STASH = map("obj16/stash.png"); //$NON-NLS-1$
- STASH_APPLY = map("obj16/stash-apply.png"); //$NON-NLS-1$
- STASH_CREATE = map("obj16/stash-create.png"); //$NON-NLS-1$
- HISTORY = map("obj16/history.png"); //$NON-NLS-1$
- SEARCH_COMMIT = map("obj16/search-commit.png"); //$NON-NLS-1$
- HIERARCHY = map("elcl16/hierarchicalLayout.png"); //$NON-NLS-1$
- FLAT = map("elcl16/flatLayout.png"); //$NON-NLS-1$
- COMPACT = map("elcl16/compactLayout.png"); //$NON-NLS-1$
- SQUASH_UP = map("obj16/squash-up.png"); //$NON-NLS-1$
- SQUASH_DOWN = map("obj16/squash-down.png"); //$NON-NLS-1$
- FIXUP_UP = map("obj16/fixup-up.png"); //$NON-NLS-1$
- FIXUP_DOWN = map("obj16/fixup-down.png"); //$NON-NLS-1$
- REVERT = map("obj16/revert.png"); //$NON-NLS-1$
- REWORD = map("obj16/reword.png"); //$NON-NLS-1$
- DONE_STEP = map("obj16/done_step.png"); //$NON-NLS-1$
- CURRENT_STEP = map("obj16/current_step.png"); //$NON-NLS-1$
- ALPHABETICALLY_SORT = map("obj16/alphab_sort_co.png"); //$NON-NLS-1$
- STATE_SORT = map("obj16/state_sort_co.png"); //$NON-NLS-1$
- UNSTAGE = map("obj16/unstage.png"); //$NON-NLS-1$
- UNSTAGE_ALL = map("elcl16/unstage_all.png"); //$NON-NLS-1$
- ASSUME_UNCHANGED = map("obj16/assume_unchanged.png"); //$NON-NLS-1$
- UNTRACK = map("obj16/untrack.png"); //$NON-NLS-1$
- IGNORE = map("obj16/ignore.png"); //$NON-NLS-1$
- GOTO_INPUT = map("elcl16/goto_input.png"); //$NON-NLS-1$
+ OVR_CHECKEDOUT = map("ovr/checkedout_ov.svg"); //$NON-NLS-1$
+ OVR_STAGED = map("ovr/staged.svg"); //$NON-NLS-1$
+ OVR_STAGED_ADD = map("ovr/staged_added.svg"); //$NON-NLS-1$
+ OVR_STAGED_REMOVE = map("ovr/staged_removed.svg"); //$NON-NLS-1$
+ OVR_STAGED_RENAME = map("ovr/staged_renamed.svg"); //$NON-NLS-1$
+ OVR_UNTRACKED = map("ovr/untracked.svg"); //$NON-NLS-1$
+ OVR_CONFLICT = map("ovr/conflict.svg"); //$NON-NLS-1$
+ OVR_DELETE_MODIFY = map("ovr/delete_modify.svg"); //$NON-NLS-1$
+ OVR_MODIFY_DELETE = map("ovr/modify_delete.svg"); //$NON-NLS-1$
+ OVR_ASSUMEUNCHANGED = map("ovr/assume_unchanged.svg"); //$NON-NLS-1$
+ OVR_DIRTY = map("ovr/dirty.svg"); //$NON-NLS-1$
+ OVR_SYMLINK = map("ovr/symlink_ovr.svg"); //$NON-NLS-1$
+ ELCL16_FIND = map("elcl16/find.svg"); //$NON-NLS-1$
+ ELCL16_COMPARE_VIEW = map("elcl16/compare_view.svg"); //$NON-NLS-1$
+ ELCL16_NEXT = map("elcl16/next_nav.svg"); //$NON-NLS-1$
+ ELCL16_PREVIOUS = map("elcl16/prev_nav.svg"); //$NON-NLS-1$
+ WIZBAN_CREATE_PATCH = map("wizban/createpatch_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_IMPORT_REPO = map("wizban/import_wiz.svg"); //$NON-NLS-1$
+ WIZBAN_CONNECT_REPO = map("wizban/newconnect_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_COMMIT = map("wizban/commit_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_FETCH_GERRIT = map("wizban/fetch_gerrit_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_FETCH = map("wizban/fetch_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_PULL = map("wizban/pull_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_PUSH_GERRIT = map("wizban/push_gerrit_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_PUSH = map("wizban/push_wizban.svg"); //$NON-NLS-1$
+ WIZBAN_SYNCHRONIZE = map("wizban/synchronize_wizban.svg"); //$NON-NLS-1$
+ EDITCONFIG = map("obj16/editconfig.svg"); //$NON-NLS-1$
+ ELCL16_COMMIT = map("elcl16/commit.svg"); //$NON-NLS-1$
+ ELCL16_COMMENTS = map("elcl16/comment.svg"); //$NON-NLS-1$
+ ELCL16_AUTHOR = map("elcl16/author.svg"); //$NON-NLS-1$
+ ELCL16_COMMITTER = map("elcl16/committer.svg"); //$NON-NLS-1$
+ ELCL16_DELETE = map("elcl16/delete.svg"); //$NON-NLS-1$
+ ELCL16_ADD = map("elcl16/add.svg"); //$NON-NLS-1$
+ ELCL16_ADD_ALL = map("elcl16/add_all.svg"); //$NON-NLS-1$
+ ELCL16_TRASH = map("elcl16/trash_flat.svg"); //$NON-NLS-1$
+ ELCL16_CLEAR = map("elcl16/clear_co.svg"); //$NON-NLS-1$
+ ELCL16_REFRESH = map("elcl16/refresh.svg"); //$NON-NLS-1$
+ ELCL16_SYNCED = map("elcl16/synced.svg"); //$NON-NLS-1$
+ ELCL16_ID = map("elcl16/sha1.svg"); //$NON-NLS-1$
+ ELCL16_COLUMN_LAYOUT = map("elcl16/horizontal_view.svg"); //$NON-NLS-1$
+ ELCL16_FILTER = map("elcl16/filter_ps_funnel.svg"); //$NON-NLS-1$
+ ELCL16_PREVIEW = map("elcl16/preview.svg"); //$NON-NLS-1$
+ ELCL16_HIDE_UNTRACKED = map("elcl16/hide_untracked.svg"); //$NON-NLS-1$
+ FILTERNONE = map("elcl16/filter_none_funnel.svg"); //$NON-NLS-1$
+ FILTERRESOURCE = map("elcl16/filter_resource_funnel.svg"); //$NON-NLS-1$
+ FILTERPROJECT = map("elcl16/filter_project_funnel.svg"); //$NON-NLS-1$
+ FILTERFOLDER = map("elcl16/filter_folder_funnel.svg"); //$NON-NLS-1$
+ FETCH = map("obj16/fetch.svg"); //$NON-NLS-1$
+ PUSH = map("obj16/push.svg"); //$NON-NLS-1$
+ PULL = map("obj16/pull.svg"); //$NON-NLS-1$
+ REPOSITORY = map("obj16/repository_rep.svg"); //$NON-NLS-1$
+ REPOSITORY_GERRIT = map("obj16/repository_gerrit.svg"); //$NON-NLS-1$
+ NEW_REPOSITORY = map("etool16/newlocation_wiz.svg"); //$NON-NLS-1$
+ REMOTE_REPOSITORY = map("obj16/remote_entry_tbl.svg"); //$NON-NLS-1$
+ REMOTE_SPEC = map("obj16/synchronize.svg"); //$NON-NLS-1$
+ BRANCHES = map("obj16/branches_obj.svg"); //$NON-NLS-1$
+ TAGS = map("obj16/tags.svg"); //$NON-NLS-1$
+ TAG = map("obj16/version_rep.svg"); //$NON-NLS-1$
+ CREATE_TAG = map("obj16/new_tag_obj.svg"); //$NON-NLS-1$
+ BRANCH = map("obj16/branch_obj.svg"); //$NON-NLS-1$
+ CREATE_BRANCH = map("obj16/new_branch_obj.svg"); //$NON-NLS-1$
+ COLLAPSEALL = map("elcl16/collapseall.svg"); //$NON-NLS-1$
+ CLONEGIT = map("obj16/cloneGit.svg"); //$NON-NLS-1$
+ RESET = map("obj16/reset.svg"); //$NON-NLS-1$
+ CHANGESET = map("obj16/changelog_obj.svg"); //$NON-NLS-1$
+ GERRIT = map("obj16/gerrit_obj.svg"); //$NON-NLS-1$
+ EXPAND_ALL = map("elcl16/expandall.svg"); //$NON-NLS-1$
+ CHECKOUT = map("obj16/checkout.svg"); //$NON-NLS-1$
+ SIGNED_OFF = map("obj16/signed-off.svg"); //$NON-NLS-1$
+ CHECK_ALL = map("obj16/check_all.svg"); //$NON-NLS-1$
+ UNCHECK_ALL = map("obj16/uncheck_all.svg"); //$NON-NLS-1$
+ AMEND_COMMIT = map("obj16/commit_amend.svg"); //$NON-NLS-1$
+ UNTRACKED_FILE = map("obj16/untracked_file.svg"); //$NON-NLS-1$
+ NOTE = map("obj16/note.svg"); //$NON-NLS-1$
+ ANNOTATE = map("etool16/annotate.svg"); //$NON-NLS-1$
+ COMMIT = map("obj16/commit.svg"); //$NON-NLS-1$
+ CHERRY_PICK = map("obj16/cherry-pick.svg"); //$NON-NLS-1$
+ REBASE = map("obj16/rebase.svg"); //$NON-NLS-1$
+ REBASE_CONTINUE = map("elcl16/continue.svg"); //$NON-NLS-1$
+ REBASE_SKIP = map("elcl16/skip.svg"); //$NON-NLS-1$
+ REBASE_ABORT = map("elcl16/progress_stop.svg"); //$NON-NLS-1$
+ REBASE_PROCESS_STEPS = map("elcl16/start.svg"); //$NON-NLS-1$
+ OVR_ERROR = map("ovr/error.svg"); //$NON-NLS-1$
+ MERGE = map("obj16/merge.svg"); //$NON-NLS-1$
+ FIRST_PARENT_ONLY = map("obj16/first_parent_only.svg"); //$NON-NLS-1$
+ TAG_ANNOTATED = map("obj16/annotated-tag.svg"); //$NON-NLS-1$
+ CREATE_REPOSITORY = map("etool16/createRepository.svg"); //$NON-NLS-1$
+ SUBMODULES = map("obj16/submodules.svg"); //$NON-NLS-1$
+ CLEAN = map("obj16/clean_obj.svg"); //$NON-NLS-1$
+ STASH = map("obj16/stash.svg"); //$NON-NLS-1$
+ STASH_APPLY = map("obj16/stash-apply.svg"); //$NON-NLS-1$
+ STASH_CREATE = map("obj16/stash-create.svg"); //$NON-NLS-1$
+ HISTORY = map("obj16/history.svg"); //$NON-NLS-1$
+ SEARCH_COMMIT = map("obj16/search-commit.svg"); //$NON-NLS-1$
+ HIERARCHY = map("elcl16/hierarchicalLayout.svg"); //$NON-NLS-1$
+ FLAT = map("elcl16/flatLayout.svg"); //$NON-NLS-1$
+ COMPACT = map("elcl16/compactLayout.svg"); //$NON-NLS-1$
+ SQUASH_UP = map("obj16/squash-up.svg"); //$NON-NLS-1$
+ SQUASH_DOWN = map("obj16/squash-down.svg"); //$NON-NLS-1$
+ FIXUP_UP = map("obj16/fixup-up.svg"); //$NON-NLS-1$
+ FIXUP_DOWN = map("obj16/fixup-down.svg"); //$NON-NLS-1$
+ REVERT = map("obj16/revert.svg"); //$NON-NLS-1$
+ REWORD = map("obj16/reword.svg"); //$NON-NLS-1$
+ DONE_STEP = map("obj16/done_step.svg"); //$NON-NLS-1$
+ CURRENT_STEP = map("obj16/current_step.svg"); //$NON-NLS-1$
+ ALPHABETICALLY_SORT = map("obj16/alphab_sort_co.svg"); //$NON-NLS-1$
+ STATE_SORT = map("obj16/state_sort_co.svg"); //$NON-NLS-1$
+ UNSTAGE = map("obj16/unstage.svg"); //$NON-NLS-1$
+ UNSTAGE_ALL = map("elcl16/unstage_all.svg"); //$NON-NLS-1$
+ ASSUME_UNCHANGED = map("obj16/assume_unchanged.svg"); //$NON-NLS-1$
+ UNTRACK = map("obj16/untrack.svg"); //$NON-NLS-1$
+ IGNORE = map("obj16/ignore.svg"); //$NON-NLS-1$
+ GOTO_INPUT = map("elcl16/goto_input.svg"); //$NON-NLS-1$
CHECKED_OUT_BRANCH = new DecorationOverlayIcon(BRANCH,
OVR_CHECKEDOUT, IDecoration.TOP_LEFT);
- SIGN_COMMIT = map("obj16/sign-commit.png"); //$NON-NLS-1$
- MERGE_TOOL = map("obj16/mergetool.png"); //$NON-NLS-1$
- OPEN_COMMIT = map("obj16/open-commit.png"); //$NON-NLS-1$
- REMOVE_FROM_REPO_GROUP = map("obj16/clear.png"); //$NON-NLS-1$
- IGNORE_LEFT_CHANGES = map("etool16/merge_ignore_left.png"); //$NON-NLS-1$
- IGNORE_RIGHT_CHANGES = map("etool16/merge_ignore_right.png"); //$NON-NLS-1$
- SETTINGS = map("obj16/settings.png"); //$NON-NLS-1$
+ SIGN_COMMIT = map("obj16/sign-commit.svg"); //$NON-NLS-1$
+ MERGE_TOOL = map("obj16/mergetool.svg"); //$NON-NLS-1$
+ OPEN_COMMIT = map("obj16/open-commit.svg"); //$NON-NLS-1$
+ REMOVE_FROM_REPO_GROUP = map("obj16/clear.svg"); //$NON-NLS-1$
+ IGNORE_LEFT_CHANGES = map("etool16/merge_ignore_left.svg"); //$NON-NLS-1$
+ IGNORE_RIGHT_CHANGES = map("etool16/merge_ignore_right.svg"); //$NON-NLS-1$
+ SETTINGS = map("obj16/settings.svg"); //$NON-NLS-1$
SETTINGS_FORCE = new DecorationOverlayIcon(SETTINGS, OVR_STAGED_ADD,
IDecoration.TOP_RIGHT);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
index 79a002b338..bb271647ff 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
@@ -366,9 +366,6 @@ public class UIText extends NLS {
/** */
public static String ExistingOrNewPage_InternalModeCheckbox;
- /** */
- public static String ExistingOrNewPage_NestedProjectErrorMessage;
-
/** */
public static String ExistingOrNewPage_NewLocationTargetHeader;
@@ -813,6 +810,12 @@ public class UIText extends NLS {
/** */
public static String GitPreferenceRoot_lfsSupportSuccessMessage;
+ /** */
+ public static String GitPreferenceRoot_clipboardHeader;
+
+ /** */
+ public static String GitPreferenceRoot_clipboardLabel;
+
/** */
public static String GitPreferenceRoot_lfsSupportSuccessTitle;
@@ -3018,6 +3021,19 @@ public class UIText extends NLS {
/** */
public static String PushResultDialog_title;
+ /** */
+ public static String PushResultNotification_Title;
+
+ /** */
+ public static String PushResultNotification_UpToDate;
+
+ /** */
+ public static String PushResultNotification_RefsUpdated;
+ /** */
+ public static String PushResultNotification_PushRejected;
+ /** */
+ public static String PushResultNotification_Details;
+
/** */
public static String PushResultTable_MessageText;
@@ -3306,6 +3322,30 @@ public class UIText extends NLS {
/** */
public static String FetchResultDialog_CloseButton;
+ /** */
+ public static String FetchResultNotification_Title;
+
+ /** */
+ public static String FetchResultNotification_UpToDate;
+
+ /** */
+ public static String FetchResultNotification_RefsUpdated;
+
+ /** */
+ public static String FetchResultNotification_Details;
+
+ /** */
+ public static String StashApplyResultNotification_Title;
+
+ /** */
+ public static String StashApplyResultNotification_Message;
+
+ /** */
+ public static String StashCreateResultNotification_Title;
+
+ /** */
+ public static String StashCreateResultNotification_Message;
+
/** */
public static String FetchResultTable_addingChildren;
@@ -4217,9 +4257,18 @@ public class UIText extends NLS {
/** */
public static String DialogsPreferencePage_ShowFetchInfoDialog;
+ /** */
+ public static String DialogsPreferencePage_FetchShowNotification;
+
+ /** */
+ public static String DialogsPreferencePage_StashApplyShowNotification;
+
/** */
public static String DialogsPreferencePage_ShowPushInfoDialog;
+ /** */
+ public static String DialogsPreferencePage_PushShowNotification;
+
/** */
public static String DialogsPreferencePage_ShowTooltip;
@@ -6091,6 +6140,15 @@ public class UIText extends NLS {
/** */
public static String StagingView_NoSelectionTitle;
+ /** */
+ public static String StagingView_RepoTooltipRepository;
+
+ /** */
+ public static String StagingView_RepoTooltipPath;
+
+ /** */
+ public static String StagingView_RepoTooltipBranch;
+
/** */
public static String StagingView_CompareMode;
@@ -6185,7 +6243,16 @@ public class UIText extends NLS {
public static String StagingView_CompactTree;
/** */
- public static String StagingView_Find;
+ public static String StagingView_Filter;
+
+ /** */
+ public static String StagingView_Filter_actionLabel;
+
+ /** */
+ public static String StagingView_ShowFilterTooltip;
+
+ /** */
+ public static String StagingView_HideFilterTooltip;
/** */
public static String StagingView_MergeTool;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/branch/BranchOperationUI.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/branch/BranchOperationUI.java
index 92aeb6ff45..8af3fffe7b 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/branch/BranchOperationUI.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/branch/BranchOperationUI.java
@@ -40,6 +40,7 @@
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.UIRepositoryUtils;
import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.egit.ui.internal.decorators.DecoratorRepositoryStateCache;
import org.eclipse.egit.ui.internal.decorators.GitLightweightDecorator;
import org.eclipse.egit.ui.internal.dialogs.NonDeletedFilesDialog;
import org.eclipse.egit.ui.internal.repository.CreateBranchWizard;
@@ -278,6 +279,8 @@ public IStatus run(IProgressMonitor monitor) {
return Activator
.createErrorStatus(UIText.BranchAction_branchFailed, e);
} finally {
+ Arrays.stream(repositories)
+ .forEach(DecoratorRepositoryStateCache.INSTANCE::clear);
GitLightweightDecorator.refresh();
monitor.done();
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clipboard/ClipboardPropertyTester.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clipboard/ClipboardPropertyTester.java
index 0cc999f8f5..c1947fedd3 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clipboard/ClipboardPropertyTester.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/clipboard/ClipboardPropertyTester.java
@@ -13,6 +13,9 @@
 *******************************************************************************/
package org.eclipse.egit.ui.internal.clipboard;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.clone.GitUrlChecker;
import org.eclipse.egit.ui.internal.expressions.AbstractPropertyTester;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
@@ -55,27 +58,39 @@ public boolean test(Object receiver, String property, Object[] args,
}
private boolean internalTest(String property) {
- if (property.equals("containsGitURL")) { //$NON-NLS-1$
- String content = getClipboardTextContent();
- if (content != null) {
+ if (!"containsGitURL".equals(property)) { //$NON-NLS-1$
+ return false;
+ }
+ if (!isClipboarMonitoringEnabled()) {
+ return false;
+ }
+ String content = getClipboardTextContent();
+ if (content != null) {
- String sanitized = GitUrlChecker
- .sanitizeAsGitUrl(content);
+ String sanitized = GitUrlChecker.sanitizeAsGitUrl(content);
- if (GitUrlChecker.isValidGitUrl(sanitized)) {
- // The clipboard is valid for GIT paste only if the current
- // swt control is not a Text or a StyledText (ie : in a
- // CellEditor)
- Control c = getFocusedControl();
- return (c != null) && !(c instanceof StyledText)
- && !(c instanceof Text);
- }
+ if (GitUrlChecker.isValidGitUrl(sanitized)) {
+ // The clipboard is valid for GIT paste only if the current
+ // swt control is not a Text or a StyledText (ie : in a
+ // CellEditor)
+ Control c = getFocusedControl();
+ return (c != null) && !(c instanceof StyledText)
+ && !(c instanceof Text);
}
}
-
return false;
}
+ /**
+ * Tells whether "Monitor clipboard for repository url" is currently enabled
+ *
+ * @return {@code true} if monitoring is enabled, {@code false} otherwise.
+ */
+ public static boolean isClipboarMonitoringEnabled() {
+ return Platform.getPreferencesService().getBoolean(Activator.PLUGIN_ID,
+ UIPreferences.ENABLE_CLIPBOARD_MONITORING, false, null);
+ }
+
/**
* Extract the text value in the clipboard.
*
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditor.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditor.java
index 10770ef1fc..de5ad9772c 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditor.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditor.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011, 2020 GitHub Inc. and others.
+ * Copyright (c) 2011, 2026 GitHub Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -9,7 +9,7 @@
*
* Contributors:
* Kevin Sawicki (GitHub Inc.) - initial API and implementation
- * Thomas Wolf - turn it into a real text editor
+ * Thomas Wolf - turn it into a real text editor
*******************************************************************************/
package org.eclipse.egit.ui.internal.commit;
@@ -71,6 +71,7 @@
import org.eclipse.jface.text.source.projection.ProjectionSupport;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
@@ -258,10 +259,23 @@ protected ISourceViewer createSourceViewer(Composite parent,
DiffViewer viewer = new DiffViewer(parent, ruler, getOverviewRuler(),
isOverviewRulerVisible(), styles,
getSite().getService(IContextService.class)) {
+
@Override
protected void setFont(Font font) {
// Don't do anything; AbstractTextEditor handles this.
}
+
+ @Override
+ protected void handleEditorPreferencesChange(
+ PropertyChangeEvent event) {
+ // Don't do anything; AbstractTextEditor handles this.
+ }
+
+ @Override
+ protected void handleJFacePreferencesChange(
+ PropertyChangeEvent event) {
+ // Don't do anything; AbstractTextEditor handles this.
+ }
};
getSourceViewerDecorationSupport(viewer);
ProjectionSupport projector = new ProjectionSupport(viewer,
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java
index b083c991f9..1203c67df2 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffEditorOutlinePage.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2016, Thomas Wolf
+ * Copyright (C) 2016, 2026 Thomas Wolf
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -33,7 +33,6 @@
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.dialogs.Dialog;
-import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.IPreferenceStore;
@@ -181,7 +180,7 @@ private TreeViewer getTreeViewerChecked() {
* if an identical listener is already registered.
*
* @param listener
- * to add to the page'sviewer
+ * to add to the page's viewer
*/
public void addOpenListener(IOpenListener listener) {
openListeners.addIfAbsent(listener);
@@ -192,7 +191,7 @@ public void addOpenListener(IOpenListener listener) {
* the listener is not registered.
*
* @param listener
- * to remove from this page's viewer.
+ * to remove from this page's viewer
*/
public void removeOpenListener(IOpenListener listener) {
openListeners.remove(listener);
@@ -225,6 +224,10 @@ public void run() {
}
private void createContextMenu(TreeViewer viewer) {
+ if (getSite() == null) {
+ // We've been opened via the QuickOutlinePopup: no context menu.
+ return;
+ }
MenuManager contextMenu = new MenuManager();
contextMenu.setRemoveAllWhenShown(true);
contextMenu.addMenuListener(menuManager -> {
@@ -527,7 +530,7 @@ public void dispose() {
}
/**
- * Opens a quick outline analgous to the outline page with tree filter
+ * Opens a quick outline analogous to the outline page with tree filter
* capability.
*
* @param document
@@ -559,7 +562,7 @@ public QuickOutlinePopup(IDocument document,
public QuickOutlinePopup(Shell parent, IDocument document,
ISelectionProvider selectionProvider) {
- super(parent, SWT.RESIZE, true, false, true, true, true,
+ super(parent, SWT.RESIZE, true, false, false, true, false,
UIText.DiffEditor_QuickOutlineAction,
UIText.DiffEditor_QuickOutlineFilterDescription);
delegate = new DiffEditorOutlinePage();
@@ -700,7 +703,6 @@ public void widgetDefaultSelected(SelectionEvent e) {
}
}
});
- tree.setMenu(null);
return delegate.getTreeViewer().getControl();
}
@@ -718,20 +720,6 @@ public boolean close() {
return super.close();
}
- @Override
- protected IDialogSettings getDialogSettings() {
- String sectionName = "diffEditor.quickoutline"; //$NON-NLS-1$
-
- IDialogSettings settings = Activator.getDefault()
- .getDialogSettings().getSection(sectionName);
- if (settings == null) {
- settings = Activator.getDefault().getDialogSettings()
- .addNewSection(sectionName);
- }
-
- return settings;
- }
-
@Override
protected Point getDefaultLocation(Point initialSize) {
IEditorPart editor = PlatformUI.getWorkbench()
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/StashApplyHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/StashApplyHandler.java
index a91f127a84..a1000fd99a 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/StashApplyHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/command/StashApplyHandler.java
@@ -24,8 +24,12 @@
import org.eclipse.egit.core.op.StashApplyOperation;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
+import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.handler.SelectionHandler;
+import org.eclipse.egit.ui.internal.stash.StashApplyResultNotification;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -60,6 +64,14 @@ public IStatus runInWorkspace(IProgressMonitor monitor) {
Utils.getShortObjectId(commit),
e.getLocalizedMessage()), e);
}
+ if (Activator.getDefault().getPreferenceStore()
+ .getBoolean(UIPreferences.STASH_APPLY_SHOW_NOTIFICATION)) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
+ Shell shell = PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getShell();
+ StashApplyResultNotification.open(shell, repo, commit);
+ });
+ }
return Status.OK_STATUS;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/DropDownMenuAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/DropDownMenuAction.java
index b65c3ef1ca..bdc8059950 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/DropDownMenuAction.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/components/DropDownMenuAction.java
@@ -33,14 +33,49 @@
* {@link #runWithEvent(Event)} or {@link #run()}.
*/
public abstract class DropDownMenuAction extends Action
- implements IWorkbenchAction, IMenuCreator {
+ implements IWorkbenchAction {
- private Menu controlMenu;
+ private class MenuCreator implements IMenuCreator {
- private Menu subMenu;
+ private Menu controlMenu;
+
+ private Menu subMenu;
+
+ private Menu dispose(Menu m) {
+ if (m != null) {
+ if (!m.isDisposed()) {
+ m.dispose();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Menu getMenu(Menu parent) {
+ subMenu = dispose(subMenu);
+ subMenu = fillMenu(new Menu(parent));
+ return subMenu;
+ }
+
+ @Override
+ public Menu getMenu(Control parent) {
+ controlMenu = dispose(controlMenu);
+ controlMenu = fillMenu(new Menu(parent));
+ return controlMenu;
+ }
+
+ @Override
+ public void dispose() {
+ controlMenu = dispose(controlMenu);
+ subMenu = dispose(subMenu);
+ }
+
+ }
private boolean showMenu;
+ private IMenuCreator menuCreator = new MenuCreator();
+
/**
* Creates a new {@link DropDownMenuAction}.
*
@@ -78,7 +113,7 @@ public void runWithEvent(Event event) {
@Override
public IMenuCreator getMenuCreator() {
- return this;
+ return menuCreator;
}
private Menu fillMenu(Menu m) {
@@ -88,29 +123,6 @@ private Menu fillMenu(Menu m) {
return m;
}
- private Menu dispose(Menu m) {
- if (m != null) {
- if (!m.isDisposed()) {
- m.dispose();
- }
- }
- return null;
- }
-
- @Override
- public Menu getMenu(Menu parent) {
- subMenu = dispose(subMenu);
- subMenu = fillMenu(new Menu(parent));
- return subMenu;
- }
-
- @Override
- public Menu getMenu(Control parent) {
- controlMenu = dispose(controlMenu);
- controlMenu = fillMenu(new Menu(parent));
- return controlMenu;
- }
-
/**
* Obtains the items to display in the drop-down menu. Might be action
* contributions or separators.
@@ -121,8 +133,7 @@ public Menu getMenu(Control parent) {
@Override
public void dispose() {
- controlMenu = dispose(controlMenu);
- subMenu = dispose(subMenu);
+ menuCreator.dispose();
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecorator.java
index 3b15d5628c..3170f8b4de 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecorator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitDecorator.java
@@ -28,6 +28,7 @@
import org.eclipse.jgit.events.ConfigChangedListener;
import org.eclipse.jgit.events.ListenerHandle;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
/**
@@ -85,8 +86,11 @@ protected void postLabelEvent() {
protected void fireLabelEvent() {
LabelProviderChangedEvent event = new LabelProviderChangedEvent(this);
// Re-trigger decoration process (in UI thread)
- PlatformUI.getWorkbench().getDisplay()
- .asyncExec(() -> fireLabelProviderChanged(event));
+ Display display = PlatformUI.getWorkbench().getDisplay();
+ if (display == null || display.isDisposed()) {
+ return;
+ }
+ display.asyncExec(() -> fireLabelProviderChanged(event));
}
@Override
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
index 6e74ad374a..0c7927a821 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java
@@ -42,6 +42,7 @@
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.UIUtils;
+import org.eclipse.egit.ui.commit.CommitContext;
import org.eclipse.egit.ui.internal.CompareUtils;
import org.eclipse.egit.ui.internal.GitLabels;
import org.eclipse.egit.ui.internal.UIIcons;
@@ -63,6 +64,8 @@
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.IMessageProvider;
@@ -115,6 +118,7 @@
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
@@ -128,6 +132,7 @@
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
@@ -138,6 +143,7 @@
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
+import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
import org.eclipse.ui.progress.WorkbenchJob;
@@ -195,7 +201,7 @@ private Image getEditorImage(CommitItem item) {
if (name != null) {
ImageDescriptor descriptor = PlatformUI.getWorkbench()
.getEditorRegistry().getImageDescriptor(name);
- image = (Image) this.resourceManager.get(descriptor);
+ image = this.resourceManager.get(descriptor);
}
return image;
} else
@@ -205,7 +211,7 @@ private Image getEditorImage(CommitItem item) {
private Image getDecoratedImage(Image base, ImageDescriptor decorator) {
DecorationOverlayIcon decorated = new DecorationOverlayIcon(base,
decorator, IDecoration.BOTTOM_RIGHT);
- return (Image) this.resourceManager.get(decorated);
+ return this.resourceManager.get(decorated);
}
@Override
@@ -364,13 +370,13 @@ public boolean select(Viewer viewer, Object parentElement,
Text committerText;
- ToolItem amendingItem;
+ private Action signedOffByAction;
- ToolItem signedOffItem;
+ private Action addChangeIdAction;
- ToolItem signCommitItem;
+ private Action amendPreviousCommitAction;
- ToolItem changeIdItem;
+ private Action signCommitAction;
ToolItem showUntrackedItem;
@@ -1027,8 +1033,8 @@ public void widgetSelected(SelectionEvent e) {
});
if (!allowToChangeSelection) {
- amendingItem.setSelection(false);
- amendingItem.setEnabled(false);
+ amendPreviousCommitAction.setChecked(false);
+ amendPreviousCommitAction.setEnabled(false);
showUntrackedItem.setSelection(false);
showUntrackedItem.setEnabled(false);
checkAllItem.setEnabled(false);
@@ -1067,6 +1073,32 @@ private void updateCommitButtons(boolean enable) {
commitButton.setEnabled(enable);
}
+ private static RowLayout createRowLayoutWithoutMargin() {
+ RowLayout layout = new RowLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layout.marginTop = 0;
+ layout.marginBottom = 0;
+ layout.marginLeft = 0;
+ layout.marginRight = 0;
+ return layout;
+ }
+
+ private void addContributions(ToolBarManager toolBarManager,
+ Composite container) {
+ IMenuService menuService = PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getService(IMenuService.class);
+ if (menuService != null) {
+ String toolbarUri = "toolbar:" //$NON-NLS-1$
+ + CommitContext.COMMIT_MSG_TOOLBAR_ID;
+ menuService.populateContributionManager(toolBarManager, toolbarUri);
+ container.addDisposeListener(event -> {
+ menuService.releaseContributions(toolBarManager);
+ toolBarManager.dispose();
+ });
+ }
+ }
+
private Composite createMessageAndPersonArea(Composite container) {
Composite messageAndPersonArea = toolkit.createComposite(container);
@@ -1090,10 +1122,13 @@ private Composite createMessageAndPersonArea(Composite container) {
GridLayoutFactory.fillDefaults().spacing(0, 0).numColumns(2)
.applyTo(headerArea);
- ToolBar messageToolbar = new ToolBar(headerArea, SWT.FLAT
- | SWT.HORIZONTAL);
+ Composite toolbarContainer = new Composite(headerArea, SWT.NONE);
+ toolbarContainer.setBackground(null);
+ toolbarContainer.setLayout(createRowLayoutWithoutMargin());
GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL)
- .grab(true, false).applyTo(messageToolbar);
+ .grab(true, false).applyTo(toolbarContainer);
+ ToolBarManager messageToolbar = new ToolBarManager(SWT.FLAT
+ | SWT.HORIZONTAL);
addMessageDropDown(headerArea);
@@ -1158,48 +1193,76 @@ protected CommitProposalProcessor getCommitProposalProcessor() {
if (committer != null)
committerText.setText(committer);
- amendingItem = new ToolItem(messageToolbar, SWT.CHECK);
- amendingItem.setSelection(amending);
- if (amending)
- amendingItem.setEnabled(false); // if already set, don't allow any
- // changes
- else if (!amendAllowed)
- amendingItem.setEnabled(false);
- amendingItem.setToolTipText(UIText.CommitDialog_AmendPreviousCommit);
- Image amendImage = UIIcons.AMEND_COMMIT.createImage();
- UIUtils.hookDisposal(amendingItem, amendImage);
- amendingItem.setImage(amendImage);
-
- signedOffItem = new ToolItem(messageToolbar, SWT.CHECK);
-
- signedOffItem.setToolTipText(UIText.CommitDialog_AddSOB);
- Image signedOffImage = UIIcons.SIGNED_OFF.createImage();
- UIUtils.hookDisposal(signedOffItem, signedOffImage);
- signedOffItem.setImage(signedOffImage);
-
- signCommitItem = new ToolItem(messageToolbar, SWT.CHECK);
-
- signCommitItem.setToolTipText(UIText.CommitDialog_SignCommit);
- Image signCommitImage = UIIcons.SIGN_COMMIT.createImage();
- UIUtils.hookDisposal(signCommitItem, signCommitImage);
- signCommitItem.setImage(signCommitImage);
-
- changeIdItem = new ToolItem(messageToolbar, SWT.CHECK);
- Image changeIdImage = UIIcons.GERRIT.createImage();
- UIUtils.hookDisposal(changeIdItem, changeIdImage);
- changeIdItem.setImage(changeIdImage);
- changeIdItem.setToolTipText(UIText.CommitDialog_AddChangeIdLabel);
+ messageToolbar
+ .add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ amendPreviousCommitAction = new Action(
+ UIText.CommitDialog_AmendPreviousCommit, IAction.AS_CHECK_BOX) {
+
+ @Override
+ public void run() {
+ commitMessageComponent.setAmendingButtonSelection(isChecked());
+ updateMessage();
+ }
+ };
+ amendPreviousCommitAction.setImageDescriptor(UIIcons.AMEND_COMMIT);
+ amendPreviousCommitAction.setChecked(amending);
+ if (amending) {
+ // If already set don't allow any changes
+ amendPreviousCommitAction.setEnabled(false);
+ } else if (!amendAllowed) {
+ amendPreviousCommitAction.setEnabled(false);
+ }
+ messageToolbar.add(amendPreviousCommitAction);
+
+ signedOffByAction = new Action(UIText.CommitDialog_AddSOB,
+ IAction.AS_CHECK_BOX) {
+
+ @Override
+ public void run() {
+ commitMessageComponent.setSignedOffButtonSelection(isChecked());
+ }
+ };
+ signedOffByAction.setImageDescriptor(UIIcons.SIGNED_OFF);
+ messageToolbar.add(signedOffByAction);
+
+ signCommitAction = new Action(UIText.CommitDialog_SignCommit,
+ IAction.AS_CHECK_BOX) {
+
+ @Override
+ public void run() {
+ commitMessageComponent
+ .setSignCommitButtonSelection(isChecked());
+ }
+ };
+ signCommitAction.setImageDescriptor(UIIcons.SIGN_COMMIT);
+ messageToolbar.add(signCommitAction);
+ signCommitAction.setEnabled(true);
+
+ addChangeIdAction = new Action(UIText.CommitDialog_AddChangeIdLabel,
+ IAction.AS_CHECK_BOX) {
+
+ @Override
+ public void run() {
+ commitMessageComponent.setChangeIdButtonSelection(isChecked());
+ }
+ };
+ addChangeIdAction.setImageDescriptor(UIIcons.GERRIT);
+ messageToolbar.add(addChangeIdAction);
+
+ addContributions(messageToolbar, toolbarContainer);
+
+ messageToolbar.createControl(toolbarContainer);
final ICommitMessageComponentNotifications listener = new ICommitMessageComponentNotifications() {
@Override
public void updateSignedOffToggleSelection(boolean selection) {
- signedOffItem.setSelection(selection);
+ signedOffByAction.setChecked(selection);
}
@Override
public void updateChangeIdToggleSelection(boolean selection) {
- changeIdItem.setSelection(selection);
+ addChangeIdAction.setChecked(selection);
if (isGerritRepo) {
pushSettings.setVisible(!selection);
pushSettings.getControl().getParent().requestLayout();
@@ -1208,7 +1271,7 @@ public void updateChangeIdToggleSelection(boolean selection) {
@Override
public void updateSignCommitToggleSelection(boolean selection) {
- signCommitItem.setSelection(selection);
+ signCommitAction.setChecked(selection);
}
@Override
@@ -1229,44 +1292,17 @@ public void statusUpdated() {
commitMessageComponent.setAmending(amending);
commitMessageComponent.setFilesToCommit(getFileList());
- amendingItem.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent arg0) {
- commitMessageComponent.setAmendingButtonSelection(amendingItem
- .getSelection());
- }
- });
-
- changeIdItem.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent arg0) {
- commitMessageComponent.setChangeIdButtonSelection(changeIdItem
- .getSelection());
- }
- });
-
- signedOffItem.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent arg0) {
- commitMessageComponent
- .setSignedOffButtonSelection(signedOffItem
- .getSelection());
- }
- });
-
- signCommitItem.setEnabled(true);
- // TODO UIText.CommitDialog_Sign_Not_Available
- signCommitItem.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- commitMessageComponent.setSignCommitButtonSelection(
- signCommitItem.getSelection());
- }
- });
-
commitMessageComponent.updateUI();
commitMessageComponent.enableListeners(true);
+ container.getShell().setData(CommitContext.class.getCanonicalName(),
+ new DefaultCommitContext(commitText) {
+ @Override
+ public Repository getRepository() {
+ return repository;
+ }
+ });
+
return messageAndPersonArea;
}
@@ -1330,12 +1366,12 @@ && getPreferenceStore().getBoolean(UIPreferences.BLOCK_COMMIT)
}
private boolean isCommitWithoutFilesAllowed() {
- if (filesViewer.getCheckedElements().length > 0)
+ if (filesViewer.getCheckedElements().length > 0) {
return true;
-
- if (amendingItem.getSelection())
+ }
+ if (amendPreviousCommitAction.isChecked()) {
return true;
-
+ }
return CommitHelper.isCommitWithoutFilesAllowed(repository);
}
@@ -1522,7 +1558,7 @@ protected void okPressed() {
commitMessage = commitMessageComponent.getCommitMessage();
author = commitMessageComponent.getAuthor();
committer = commitMessageComponent.getCommitter();
- createChangeId = changeIdItem.getSelection();
+ createChangeId = addChangeIdAction.isChecked();
signCommit = commitMessageComponent.isSignCommit();
IDialogSettings settings = org.eclipse.egit.ui.Activator
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageBuilder.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageBuilder.java
index 64089264be..878e6299d6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageBuilder.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageBuilder.java
@@ -27,9 +27,9 @@
import org.eclipse.egit.core.internal.util.ProjectUtil;
import org.eclipse.egit.core.internal.util.ResourceUtil;
import org.eclipse.egit.ui.Activator;
-import org.eclipse.egit.ui.CommitMessageWithCaretPosition;
-import org.eclipse.egit.ui.ICommitMessageProvider;
-import org.eclipse.egit.ui.ICommitMessageProvider2;
+import org.eclipse.egit.ui.api.CommitMessageWithCaretPosition;
+import org.eclipse.egit.ui.api.ICommitMessageProvider;
+import org.eclipse.egit.ui.api.ICommitMessageProvider2;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.jgit.lib.Repository;
@@ -104,7 +104,7 @@ private String getCommitMessage(
if (messageWithPosition == null) {
return ""; //$NON-NLS-1$
} else {
- return append(messageWithPosition.getMessage());
+ return append(messageWithPosition.message());
}
}
@@ -126,12 +126,12 @@ private int updateCaretPosition(StringBuilder currentMessage,
ICommitMessageProvider2 provider) {
int pos = currentCaretPosition;
if (currentCaretPosition == CommitMessageWithCaretPosition.NO_POSITION) {
- String providedMessage = messageWithPosition.getMessage();
+ String providedMessage = messageWithPosition.message();
if (providedMessage == null || providedMessage.trim().isEmpty()) {
return pos;
}
int providedCaretPosition = messageWithPosition
- .getDesiredCaretPosition();
+ .caretPosition();
if (providedCaretPosition == CommitMessageWithCaretPosition.NO_POSITION) {
return pos;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageComponent.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageComponent.java
index 997084329f..ac1bcfbefc 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageComponent.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitMessageComponent.java
@@ -1,6 +1,5 @@
/*******************************************************************************
* Copyright (C) 2007, Dave Watson
- * Copyright (C) 2007, Robin Rosenberg
* Copyright (C) 2007, Robin Rosenberg
* Copyright (C) 2008, Robin Rosenberg
* Copyright (C) 2007, Shawn O. Pearce
@@ -10,6 +9,7 @@
* Copyright (C) 2012, 2013 Robin Stocker
* Copyright (C) 2014 IBM Corporation (Daniel Megert )
* Copyright (C) 2015 SAP SE (Christian Georgi )
+ * Copyright (C) 2025 Thomas Wolf and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -24,17 +24,16 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.regex.Pattern;
import org.eclipse.egit.core.internal.Utils;
import org.eclipse.egit.core.internal.gerrit.GerritUtil;
import org.eclipse.egit.core.op.EGitGpgConfig;
import org.eclipse.egit.core.util.RevCommitUtils;
import org.eclipse.egit.ui.Activator;
-import org.eclipse.egit.ui.CommitMessageWithCaretPosition;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.UIUtils;
import org.eclipse.egit.ui.UIUtils.IPreviousValueProposalHandler;
+import org.eclipse.egit.ui.api.CommitMessageWithCaretPosition;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.commit.CommitHelper;
@@ -87,8 +86,6 @@
*/
public class CommitMessageComponent {
- private static final Pattern EMPTY_GERRIT_MESSAGE = Pattern
- .compile("^(?:\\h*\\n)*Change-Id: I[0-9a-fA-F]{40}\\h*(?:\\n|$)"); //$NON-NLS-1$
/**
* Status provider for whether a commit operation should be enabled or not
*/
@@ -623,16 +620,52 @@ static String formatIssuesInCommitMessage(String message) {
public boolean checkCommitInfo() {
updateStateFromUI();
- String rawText = commitText.getText();
- rawText = Utils.normalizeLineEndings(rawText);
+ String rawText = Utils.normalizeLineEndings(commitText.getText());
+ int rawFooterOffset = CommonUtils.getFooterOffset(rawText);
+ String firstFooterLine = null;
+ if (rawFooterOffset > 0) {
+ int rawFooterLineEnd = rawText.indexOf('\n', rawFooterOffset + 1);
+ if (rawFooterLineEnd < 0) {
+ rawFooterLineEnd = rawText.length();
+ }
+ firstFooterLine = rawText.substring(rawFooterOffset,
+ rawFooterLineEnd).stripTrailing();
+ if (rawText.startsWith(firstFooterLine)) {
+ // Commit message title looks like the existing first footer
+ // line: the message definitely is not empty, so we don't have
+ // to check against this footer later on.
+ firstFooterLine = null;
+ } else {
+ int firstLineEnd = rawText.indexOf('\n');
+ if (firstLineEnd > 0) {
+ String firstLine = rawText.substring(0, firstLineEnd)
+ .stripTrailing();
+ if (!firstLine.isEmpty()
+ && firstFooterLine.startsWith(firstLine)) {
+ // Same reasoning as above.
+ firstFooterLine = null;
+ }
+ }
+ }
+ }
+ // Get the fully cleaned commit message
+ String text = getCommitMessage();
boolean isEmpty = false;
- if (EMPTY_GERRIT_MESSAGE.matcher(rawText).matches()) {
- isEmpty = true;
+ int footer = CommonUtils.getFooterOffset(text);
+ if (firstFooterLine != null && footer < 0) {
+ // If we had only comments and empty lines above the footers, the
+ // first footer is now at the start of the message.
+ // That's an empty message!
+ int firstLineEnd = text.indexOf('\n');
+ if (firstLineEnd < 0) {
+ firstLineEnd = text.length();
+ }
+ if (firstLineEnd <= firstFooterLine.length()) {
+ isEmpty = firstFooterLine
+ .startsWith(text.substring(0, firstLineEnd));
+ }
} else {
- // Get the fully cleaned commit message
- String text = getCommitMessage();
// Strip footers
- int footer = CommonUtils.getFooterOffset(text);
if (footer >= 0) {
text = text.substring(0, footer);
}
@@ -879,7 +912,7 @@ String calculateCommitMessage(
if (amending)
return previousCommitMessage;
- return messageWithCaretPosition.getMessage();
+ return messageWithCaretPosition.message();
}
private int calculateCaretPosition(
@@ -892,7 +925,7 @@ private int calculateCaretPosition(
if (amending)
return previousCaretPosition;
- return messageWithCaretPosition.getDesiredCaretPosition();
+ return messageWithCaretPosition.caretPosition();
}
private void saveOriginalChangeId() {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java
index 85ec352f01..46f97f05e6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java
@@ -444,7 +444,7 @@ private void updateControls() {
else
setContentDescription(NLS.bind(
UIText.CompareTreeView_ComparingTwoVersionDescription,
- new String[] { name,
+ new Object[] { name,
CompareUtils.truncatedRevision(baseVersion),
getCompareVersionText() }));
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java
index 7bcef4f824..04a168d1f5 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CreateTagDialog.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2010, 2013 Dariusz Luksza and others.
+ * Copyright (C) 2010, 2026 Dariusz Luksza and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
@@ -82,6 +82,7 @@
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
@@ -144,6 +145,9 @@ public class CreateTagDialog extends TitleAreaDialog {
private SpellcheckableMessageArea tagMessageText;
+ // XXX: Work-around for https://github.com/eclipse-egit/egit/issues/162
+ private PaintListener layoutBugWorkaround;
+
private Button overwriteButton;
private Button signButton;
@@ -578,6 +582,13 @@ public void modifyText(ModifyEvent e) {
}
});
+ layoutBugWorkaround = event -> {
+ tagMessageText.removePaintListener(layoutBugWorkaround);
+ layoutBugWorkaround = null;
+ left.layout(true, true);
+ };
+ tagMessageText.addPaintListener(layoutBugWorkaround);
+
overwriteButton = new Button(left, SWT.CHECK);
overwriteButton.setEnabled(false);
overwriteButton.setText(UIText.CreateTagDialog_overwriteTag);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/DefaultCommitContext.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/DefaultCommitContext.java
new file mode 100644
index 0000000000..2b7e50563f
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/DefaultCommitContext.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (C) 2025, Thomas Wolf and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.dialogs;
+
+import org.eclipse.egit.core.internal.Utils;
+import org.eclipse.egit.ui.commit.CommitContext;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * A base implementation of a {@link CommitContext} that uses a
+ * {@link SpellcheckableMessageArea} for the commit message.
+ */
+public abstract class DefaultCommitContext implements CommitContext {
+
+ private final SpellcheckableMessageArea text;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param text
+ * {@link SpellcheckableMessageArea} containing the commit
+ * message
+ */
+ public DefaultCommitContext(SpellcheckableMessageArea text) {
+ this.text = text;
+ }
+
+ @Override
+ public String getCommitMessage() {
+ return Utils.normalizeLineEndings(text.getText());
+ }
+
+ @Override
+ public char getCommentChar() {
+ return text.getCommentChar();
+ }
+
+ @Override
+ public void setCommitMessage(String msg) {
+ if (msg == null) {
+ text.setText(""); //$NON-NLS-1$
+ } else {
+ String normalized = Utils.normalizeLineEndings(msg);
+ normalized = normalized.replaceAll("\n", Text.DELIMITER); //$NON-NLS-1$
+ text.setText(normalized);
+ }
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java
index 09a7ca9954..82389aced2 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/SpellcheckableMessageArea.java
@@ -88,13 +88,9 @@
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
-import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Layout;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
@@ -126,9 +122,6 @@ public class SpellcheckableMessageArea extends Composite {
private BidiSegmentListener hardWrapSegmentListener;
- // XXX: workaround for https://bugs.eclipse.org/400727
- private int brokenBidiPlatformTextWidth;
-
private IAction contentAssistAction;
private Token commentColoring;
@@ -195,15 +188,6 @@ protected void handleJFacePreferencesChange(
getTextWidget().setAlwaysShowScrollBars(false);
getTextWidget().setFont(UIUtils
.getFont(UIPreferences.THEME_CommitMessageEditorFont));
- sourceViewer.setDocument(new Document());
- int endSpacing = 2;
- int textWidth = (int) (getCharWidth() * MAX_LINE_WIDTH + endSpacing);
- int textHeight = getLineHeight() * 7;
- Point size = getTextWidget().computeSize(textWidth, textHeight);
- getTextWidget().setSize(size);
-
- computeBrokenBidiPlatformTextWidth(size.x);
-
getTextWidget().setEditable(!readOnly);
createMarginPainter();
@@ -216,9 +200,6 @@ protected void handleJFacePreferencesChange(
getDisplay().asyncExec(() -> {
if (!isDisposed()) {
configureHardWrap();
- if (brokenBidiPlatformTextWidth != -1) {
- layout();
- }
}
});
}
@@ -369,25 +350,6 @@ protected int getViewerStyles() {
return SWT.V_SCROLL | SWT.WRAP;
}
- private void computeBrokenBidiPlatformTextWidth(int textWidth) {
- class BidiSegmentListenerTester implements BidiSegmentListener {
- boolean called;
-
- @Override
- public void lineGetSegments(BidiSegmentEvent event) {
- called = true;
- }
- }
- BidiSegmentListenerTester tester = new BidiSegmentListenerTester();
- StyledText textWidget = getTextWidget();
- textWidget.addBidiSegmentListener(tester);
- textWidget.setText(" "); //$NON-NLS-1$
- textWidget.computeSize(SWT.DEFAULT, SWT.DEFAULT);
- textWidget.removeBidiSegmentListener(tester);
-
- brokenBidiPlatformTextWidth = tester.called ? -1 : textWidth;
- }
-
private boolean isEditable(ISourceViewer viewer) {
return viewer != null && viewer.isEditable();
}
@@ -421,44 +383,11 @@ public void lineGetSegments(BidiSegmentEvent e) {
}
};
textWidget.addBidiSegmentListener(hardWrapSegmentListener);
- textWidget.setText(textWidget.getText()); // XXX: workaround for https://bugs.eclipse.org/384886
-
- if (brokenBidiPlatformTextWidth != -1) {
- Layout restrictedWidthLayout = new Layout() {
- @Override
- protected Point computeSize(Composite composite,
- int wHint, int hHint, boolean flushCache) {
- Point size = SpellcheckableMessageArea.this
- .getSize();
- Rectangle trim = SpellcheckableMessageArea.this
- .computeTrim(0, 0, 0, 0);
- size.x -= trim.width;
- size.y -= trim.height;
- if (size.x > brokenBidiPlatformTextWidth)
- size.x = brokenBidiPlatformTextWidth;
- return size;
- }
-
- @Override
- protected void layout(Composite composite,
- boolean flushCache) {
- Point size = computeSize(composite, SWT.DEFAULT,
- SWT.DEFAULT, flushCache);
- textWidget.setBounds(0, 0, size.x, size.y);
- }
- };
- setLayout(restrictedWidthLayout);
- }
}
-
} else if (hardWrapSegmentListener != null) {
StyledText textWidget = getTextWidget();
textWidget.removeBidiSegmentListener(hardWrapSegmentListener);
- textWidget.setText(textWidget.getText()); // XXX: workaround for https://bugs.eclipse.org/384886
hardWrapSegmentListener = null;
-
- if (brokenBidiPlatformTextWidth != -1)
- setLayout(new FillLayout());
}
}
@@ -616,17 +545,6 @@ protected void createMarginPainter() {
sourceViewer.addPainter(marginPainter);
}
- private double getCharWidth() {
- GC gc = new GC(getTextWidget());
- double charWidth = gc.getFontMetrics().getAverageCharacterWidth();
- gc.dispose();
- return charWidth;
- }
-
- private int getLineHeight() {
- return getTextWidget().getLineHeight();
- }
-
/**
* @return if the commit message should be hard-wrapped (preference)
*/
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchOperationUI.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchOperationUI.java
index da5be1ae2b..6f0f73e822 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchOperationUI.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchOperationUI.java
@@ -184,9 +184,15 @@ public ShowResultAction(@NonNull Repository repository,
protected void showResult(@NonNull Repository repository) {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow()
.getShell();
- FetchResultDialog dialog = new FetchResultDialog(shell, repository,
- result, source);
- dialog.open();
+ if (Activator.getDefault().getPreferenceStore()
+ .getBoolean(UIPreferences.FETCH_SHOW_NOTIFICATION)) {
+ new FetchResultNotification(shell, repository, result, source)
+ .open();
+ } else {
+ FetchResultDialog dialog = new FetchResultDialog(shell,
+ repository, result, source);
+ dialog.open();
+ }
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchResultNotification.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchResultNotification.java
new file mode 100644
index 0000000000..99446a54a9
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/FetchResultNotification.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (C) 2026 vogella GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.fetch;
+
+import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.notifications.AbstractNotificationPopup;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.FetchResult;
+
+/**
+ * A non-blocking, auto-dismissing notification shown after a successful fetch
+ * operation when the user has enabled the notification preference. Uses Eclipse's
+ * {@link AbstractNotificationPopup} for proper fade animation and positioning.
+ */
+public class FetchResultNotification extends AbstractNotificationPopup {
+
+ private static final long DELAY_CLOSE_MS = 5000;
+
+ private final Repository repository;
+
+ private final FetchResult result;
+
+ private final String source;
+
+ /**
+ * @param parent
+ * the parent shell (used to obtain the Display)
+ * @param repository
+ * the repository that was fetched
+ * @param result
+ * the fetch result
+ * @param source
+ * display string identifying the remote source
+ */
+ public FetchResultNotification(Shell parent, Repository repository,
+ FetchResult result, String source) {
+ super(parent.getDisplay());
+ setParentShell(parent);
+ this.repository = repository;
+ this.result = result;
+ this.source = source;
+ setDelayClose(DELAY_CLOSE_MS);
+ setFadingEnabled(true);
+ }
+
+ @Override
+ protected String getPopupShellTitle() {
+ return NLS.bind(UIText.FetchResultNotification_Title, source);
+ }
+
+ @Override
+ protected void createContentArea(Composite parent) {
+ GridLayoutFactory.fillDefaults().margins(4, 0).applyTo(parent);
+
+ Label body = new Label(parent, SWT.WRAP);
+ int updateCount = result.getTrackingRefUpdates().size();
+ if (updateCount == 0) {
+ body.setText(UIText.FetchResultNotification_UpToDate);
+ } else {
+ body.setText(NLS.bind(UIText.FetchResultNotification_RefsUpdated,
+ Integer.valueOf(updateCount)));
+ }
+ GridDataFactory.fillDefaults().grab(true, false).hint(280, SWT.DEFAULT)
+ .applyTo(body);
+
+ Link details = new Link(parent, SWT.NONE);
+ details.setText(
+ "" + UIText.FetchResultNotification_Details + ""); //$NON-NLS-1$ //$NON-NLS-2$
+ details.addListener(SWT.Selection, e -> {
+ close();
+ Shell activeShell = PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getShell();
+ FetchResultDialog dialog = new FetchResultDialog(activeShell,
+ repository, result, source);
+ dialog.open();
+ });
+ GridDataFactory.fillDefaults().applyTo(details);
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitAndDiffComponent.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitAndDiffComponent.java
index 681ca2ddd5..6cc08247a7 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitAndDiffComponent.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitAndDiffComponent.java
@@ -97,7 +97,8 @@ public CommitAndDiffComponent(Composite parent, IWorkbenchPartSite site) {
SWT.NONE);
commentAndDiffScrolledComposite.setContent(commentAndDiffComposite);
commentAndDiffComposite
- .setLayout(GridLayoutFactory.fillDefaults().create());
+ .setLayout(GridLayoutFactory.fillDefaults().spacing(0, 0)
+ .create());
commentViewer = new CommitMessageViewer(commentAndDiffComposite, site);
commentViewer.getControl().setLayoutData(
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
index e1b94d2526..0455fc29d1 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/CommitGraphTable.java
@@ -190,6 +190,8 @@ static Font highlightFont() {
private boolean enableAntialias = true;
+ private boolean resizeLayoutPending;
+
/**
* Creates a new {@link CommitGraphTable} using the given
* {@link TableLoader} and {@link ResourceManager} with the given style.
@@ -304,7 +306,7 @@ public void handleEvent(Event event) {
rawTable.addDisposeListener(
event -> store.removePropertyChangeListener(prefsChanged));
}
- rawTable.addListener(SWT.Resize, event -> layout(rawTable));
+ rawTable.addListener(SWT.Resize, event -> scheduleResizeLayout(rawTable));
table = new TableViewer(rawTable) {
@Override
@@ -699,6 +701,22 @@ public TableViewer getTableView() {
return table;
}
+ private void scheduleResizeLayout(Table rawTable) {
+ if (resizeLayoutPending) {
+ return;
+ }
+ resizeLayoutPending = true;
+ rawTable.getDisplay().asyncExec(() -> {
+ try {
+ if (!rawTable.isDisposed()) {
+ layout(rawTable);
+ }
+ } finally {
+ resizeLayoutPending = false;
+ }
+ });
+ }
+
private void layout(Table rawTable) {
rawTable.getParent().layout();
// Check that the table now fits
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
index 1b00d9c8ad..3e49c07971 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/history/GitHistoryPage.java
@@ -1668,7 +1668,7 @@ private void initActions() {
showAllFilter = ShowFilter.valueOf(Activator.getDefault()
.getPreferenceStore().getString(PREF_SHOWALLFILTER));
} catch (IllegalArgumentException e) {
- showAllFilter = ShowFilter.SHOWALLRESOURCE;
+ showAllFilter = ShowFilter.SHOWALLREPO;
}
actions = new GitHistoryPageActions(this);
@@ -2548,12 +2548,13 @@ private void initAndStartRevWalk(boolean forceNewWalk,
|| settingsChanged) {
releaseGenerateHistoryJob();
- if (repoChanged) {
+ if (repoChanged || pathsChanged) {
// Clear all viewers. Otherwise it may be possible that
// the user invokes a context menu command and due to to
// the highly asynchronous loading we end up with
// inconsistent diff computations trying to find the
- // diff for a commit in the wrong repository.
+ // diff for a commit in the wrong repository or path
+ // (file/folder/project).
clearViewers();
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/DialogsPreferencePage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/DialogsPreferencePage.java
index bc23bcb4e7..7e1972f522 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/DialogsPreferencePage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/DialogsPreferencePage.java
@@ -107,11 +107,17 @@ protected void createFieldEditors() {
addField(editor);
editor.getDescriptionControl(infoGroup)
.setToolTipText(UIText.DialogsPreferencePage_ShowTooltip);
+ addField(new BooleanFieldEditor(UIPreferences.FETCH_SHOW_NOTIFICATION,
+ UIText.DialogsPreferencePage_FetchShowNotification, infoGroup));
+ addField(new BooleanFieldEditor(UIPreferences.STASH_APPLY_SHOW_NOTIFICATION,
+ UIText.DialogsPreferencePage_StashApplyShowNotification, infoGroup));
editor = new BooleanFieldEditor(UIPreferences.SHOW_PUSH_POPUP_SUCCESS,
UIText.DialogsPreferencePage_ShowPushInfoDialog, infoGroup);
addField(editor);
editor.getDescriptionControl(infoGroup)
.setToolTipText(UIText.DialogsPreferencePage_ShowTooltip);
+ addField(new BooleanFieldEditor(UIPreferences.PUSH_SHOW_NOTIFICATION,
+ UIText.DialogsPreferencePage_PushShowNotification, infoGroup));
updateMargins(infoGroup);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/GitPreferenceRoot.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/GitPreferenceRoot.java
index 71b5dc3f55..d066d32a5f 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/GitPreferenceRoot.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/preferences/GitPreferenceRoot.java
@@ -392,6 +392,15 @@ public void widgetSelected(SelectionEvent e) {
}
});
updateMargins(lfsGroup);
+
+ Group clipboardGroup = new Group(main, SWT.SHADOW_ETCHED_IN);
+ GridDataFactory.fillDefaults().grab(true, false).span(GROUP_SPAN, 1)
+ .applyTo(clipboardGroup);
+ clipboardGroup.setText(UIText.GitPreferenceRoot_clipboardHeader);
+ addField(new BooleanFieldEditor(
+ UIPreferences.ENABLE_CLIPBOARD_MONITORING,
+ UIText.GitPreferenceRoot_clipboardLabel, clipboardGroup));
+ updateMargins(clipboardGroup);
}
@Override
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultNotification.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultNotification.java
new file mode 100644
index 0000000000..b2aee31d51
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/PushResultNotification.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (C) 2026 vogella GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.push;
+
+import org.eclipse.egit.core.op.PushOperationResult;
+import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.notifications.AbstractNotificationPopup;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.RemoteRefUpdate;
+import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+import org.eclipse.jgit.transport.URIish;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A non-blocking, auto-dismissing notification shown after a successful push
+ * operation when the user has enabled the notification preference. Uses
+ * Eclipse's {@link AbstractNotificationPopup} for proper fade animation and
+ * positioning.
+ */
+public class PushResultNotification extends AbstractNotificationPopup {
+
+ private static final long DELAY_CLOSE_MS = 5000;
+
+ private final Repository repository;
+
+ private final PushOperationResult result;
+
+ private final String destination;
+
+ private final boolean showConfigure;
+
+ private final @NonNull PushMode pushMode;
+
+ /**
+ * @param parent
+ * the parent shell (used to obtain the Display)
+ * @param repository
+ * the repository that was pushed
+ * @param result
+ * the push result
+ * @param destination
+ * display string identifying the remote destination
+ * @param showConfigure
+ * whether to show the configure button in the detail dialog
+ * @param pushMode
+ * the push mode used
+ */
+ public PushResultNotification(Shell parent, Repository repository,
+ PushOperationResult result, String destination,
+ boolean showConfigure, @NonNull PushMode pushMode) {
+ super(parent.getDisplay());
+ setParentShell(parent);
+ this.repository = repository;
+ this.result = result;
+ this.destination = destination;
+ this.showConfigure = showConfigure;
+ this.pushMode = pushMode;
+ setDelayClose(DELAY_CLOSE_MS);
+ setFadingEnabled(true);
+ }
+
+ @Override
+ protected String getPopupShellTitle() {
+ return NLS.bind(UIText.PushResultNotification_Title, destination);
+ }
+
+ @Override
+ protected void createContentArea(Composite parent) {
+ GridLayoutFactory.fillDefaults().margins(4, 0).applyTo(parent);
+
+ Label body = new Label(parent, SWT.WRAP);
+ int updated = 0;
+ int rejected = 0;
+ boolean upToDate = true;
+ boolean hasErrors = false;
+
+ for (URIish uri : result.getURIs()) {
+ String errorMessage = result.getErrorMessage(uri);
+ if (errorMessage != null && !errorMessage.isEmpty()) {
+ hasErrors = true;
+ continue;
+ }
+ for (RemoteRefUpdate update : result.getPushResult(uri)
+ .getRemoteUpdates()) {
+ Status status = update.getStatus();
+ if (status == Status.OK) {
+ updated++;
+ upToDate = false;
+ } else if (isRejected(status)) {
+ rejected++;
+ upToDate = false;
+ } else if (status != Status.UP_TO_DATE) {
+ upToDate = false;
+ }
+ }
+ }
+
+ if (rejected > 0 || hasErrors) {
+ body.setText(UIText.PushResultNotification_PushRejected);
+ } else if (upToDate) {
+ body.setText(UIText.PushResultNotification_UpToDate);
+ } else {
+ body.setText(NLS.bind(UIText.PushResultNotification_RefsUpdated,
+ Integer.valueOf(updated)));
+ }
+
+ GridDataFactory.fillDefaults().grab(true, false).hint(280, SWT.DEFAULT)
+ .applyTo(body);
+
+ Link details = new Link(parent, SWT.NONE);
+ details.setText(
+ "" + UIText.PushResultNotification_Details + ""); //$NON-NLS-1$ //$NON-NLS-2$
+ details.addListener(SWT.Selection, e -> {
+ close();
+ Shell activeShell = PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getShell();
+ PushResultDialog dialog = new PushResultDialog(activeShell,
+ repository, result, destination, false, pushMode);
+ dialog.showConfigureButton(showConfigure);
+ dialog.open();
+ });
+ GridDataFactory.fillDefaults().applyTo(details);
+ }
+
+ private boolean isRejected(Status status) {
+ switch (status) {
+ case REJECTED_NODELETE:
+ case REJECTED_NONFASTFORWARD:
+ case REJECTED_OTHER_REASON:
+ case REJECTED_REMOTE_CHANGED:
+ return true;
+ default:
+ return false;
+ }
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/ShowPushResultAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/ShowPushResultAction.java
index 31da2ec91b..6b7dd03905 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/ShowPushResultAction.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/ShowPushResultAction.java
@@ -11,6 +11,8 @@
package org.eclipse.egit.ui.internal.push;
import org.eclipse.egit.core.op.PushOperationResult;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.jobs.RepositoryJobResultAction;
import org.eclipse.jgit.annotations.NonNull;
@@ -67,9 +69,15 @@ private boolean isModal(Shell shell) {
protected void showResult(@NonNull Repository repository) {
Shell shell = PlatformUI.getWorkbench().getModalDialogShellProvider()
.getShell();
- PushResultDialog dialog = new PushResultDialog(shell, repository,
- operationResult, destination, isModal(shell), pushMode);
- dialog.showConfigureButton(showConfigure);
- dialog.open();
+ if (Activator.getDefault().getPreferenceStore()
+ .getBoolean(UIPreferences.PUSH_SHOW_NOTIFICATION)) {
+ new PushResultNotification(shell, repository, operationResult,
+ destination, showConfigure, pushMode).open();
+ } else {
+ PushResultDialog dialog = new PushResultDialog(shell, repository,
+ operationResult, destination, isModal(shell), pushMode);
+ dialog.showConfigureButton(showConfigure);
+ dialog.open();
+ }
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/CommitMessageEditorDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/CommitMessageEditorDialog.java
index 4c77909305..a2037623f8 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/CommitMessageEditorDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/CommitMessageEditorDialog.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2022 SAP AG and others.
+ * Copyright (c) 2013, 2026 SAP AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -43,17 +43,15 @@
import org.eclipse.jgit.lib.UserConfig;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
-import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
-import org.eclipse.ui.forms.widgets.FormToolkit;
/**
* Dialog for editing a commit message
@@ -80,6 +78,9 @@ public class CommitMessageEditorDialog extends TitleAreaDialog {
private StackLayout previewLayout;
+ // XXX: Work-around for https://github.com/eclipse-egit/egit/issues/54
+ private PaintListener layoutBugWorkaround;
+
private IAction addChangeIdAction;
private String title;
@@ -201,17 +202,6 @@ protected Control createDialogArea(Composite parent) {
GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.CENTER)
.applyTo(areaTitle);
- Composite commitMessageToolbarComposite = new Composite(titleBar,
- SWT.NONE);
- GridDataFactory.fillDefaults().grab(true, false)
- .align(SWT.END, SWT.CENTER)
- .applyTo(commitMessageToolbarComposite);
- RowLayout layout = new RowLayout();
- layout.marginTop = 0;
- layout.marginBottom = 0;
- layout.marginLeft = 0;
- layout.marginRight = 0;
- commitMessageToolbarComposite.setLayout(layout);
ToolBarManager commitMessageToolBarManager = new ToolBarManager(
SWT.FLAT | SWT.HORIZONTAL);
@@ -268,9 +258,10 @@ public void run() {
hasChangeId || GerritUtil.getCreateChangeId(config));
commitMessageToolBarManager.add(addChangeIdAction);
- ToolBar tb = commitMessageToolBarManager
- .createControl(commitMessageToolbarComposite);
+ ToolBar tb = commitMessageToolBarManager.createControl(titleBar);
tb.setBackground(null);
+ GridDataFactory.fillDefaults().grab(true, false)
+ .align(SWT.END, SWT.CENTER).applyTo(tb);
Composite commitMessageTextComposite = new Composite(
commitMessageSection, SWT.BORDER);
@@ -282,8 +273,6 @@ public void run() {
messageArea = new SpellcheckableMessageArea(commitMessageTextComposite,
"", SWT.NONE); //$NON-NLS-1$
- messageArea.setData(FormToolkit.KEY_DRAW_BORDER,
- FormToolkit.TEXT_BORDER);
CleanupMode cleanup = mode;
if (cleanup == null || CleanupMode.DEFAULT.equals(cleanup)) {
cleanup = CleanupMode.STRIP;
@@ -294,23 +283,27 @@ public void run() {
String msg = Utils.normalizeLineEndings(commitMessage).replaceAll("\n", //$NON-NLS-1$
Text.DELIMITER);
messageArea.setText(msg);
- Point size = messageArea.getTextWidget().getSize();
- int minHeight = messageArea.getTextWidget().getLineHeight() * 3;
- GridDataFactory.fillDefaults().grab(true, true)
- .hint(size).minSize(size.x, minHeight)
- .align(SWT.FILL, SWT.FILL).applyTo(messageArea);
previewArea = new Composite(commitMessageTextComposite, SWT.NONE);
- GridDataFactory.fillDefaults().grab(true, true).applyTo(previewArea);
previewArea.setLayout(new FillLayout());
- previewArea.setData(FormToolkit.KEY_DRAW_BORDER,
- FormToolkit.TEXT_BORDER);
previewer = new CommitMessagePreviewer();
previewer.createControl(previewArea);
previewLayout.topControl = messageArea;
messageArea.setFocus();
+ // Somehow the SpellCheckableMessageArea gets a negative y-coordinate on
+ // MacOS on the very first layout if the commit message has only a
+ // single line. When this happens the commit message is not visible at
+ // all. Fix this by forcing a re-layout when the message area is to be
+ // painted for the first time.
+ layoutBugWorkaround = event -> {
+ messageArea.removePaintListener(layoutBugWorkaround);
+ layoutBugWorkaround = null;
+ commitMessageTextComposite.requestLayout();
+ };
+ messageArea.addPaintListener(layoutBugWorkaround);
+
// Create two hidden text fields for author and committer, set to the
// current user, so that we can use the CommitMessageComponent. The
// committer is needed for the sign-off button; the author won't be
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java
index 74cf1adb0f..8b02031bab 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/rebase/RebaseInteractiveView.java
@@ -93,6 +93,7 @@
import org.eclipse.jgit.util.GitDateFormatter;
import org.eclipse.jgit.util.GitDateFormatter.Format;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
@@ -105,6 +106,7 @@
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
@@ -123,7 +125,6 @@
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
-import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;
@@ -166,7 +167,9 @@ public class RebaseInteractiveView extends ViewPart implements
private boolean dndEnabled = false;
- private Form form;
+ private Composite composite;
+
+ private CLabel repoLabel;
private LocalResourceManager resources = new LocalResourceManager(
JFaceResources.getResources());
@@ -281,15 +284,41 @@ public void widgetDisposed(DisposeEvent e) {
toolkit.dispose();
}
});
- form = createForm(parent, toolkit);
- createCommandToolBar(form, toolkit);
- planTreeViewer = createPlanTreeViewer(form.getBody(), toolkit);
+
+ composite = new Composite(parent, SWT.NONE);
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
+ GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0)
+ .applyTo(composite);
+
+ repoLabel = new CLabel(composite, SWT.NONE);
+ repoLabel.setImage(UIIcons.getImage(resources, UIIcons.REPOSITORY));
+ repoLabel.setText(UIText.RebaseInteractiveView_NoSelection);
+ GridDataFactory.fillDefaults().grab(true, false).indent(5, 5)
+ .applyTo(repoLabel);
+
+ Label repoSeparator = new Label(composite, SWT.SEPARATOR
+ | SWT.HORIZONTAL);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(repoSeparator);
+
+ headComposite = new Composite(composite, SWT.NONE);
+ GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false)
+ .margins(5, 2).applyTo(headComposite);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(headComposite);
+
+ createCommandToolBar(headComposite, toolkit);
+ createStepActionToolBar(toolkit);
+
+ Label headerSeparator = new Label(composite, SWT.SEPARATOR
+ | SWT.HORIZONTAL);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(headerSeparator);
+
+ planTreeViewer = createPlanTreeViewer(composite, toolkit);
planLayout = new PlanLayout();
planTreeViewer.getTree().getParent().setLayout(planLayout);
createColumns(planLayout);
- createStepActionToolBar(toolkit);
+
createPopupMenu(planTreeViewer);
setupListeners();
@@ -409,12 +438,8 @@ public void apply(boolean value) {
planTreeViewer, () -> currentRepository));
}
- private void createCommandToolBar(Form theForm, FormToolkit toolkit) {
- headComposite = new Composite(theForm.getHead(), SWT.NONE);
- theForm.setHeadClient(headComposite);
- GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false)
- .margins(0, 0).applyTo(headComposite);
- ToolBar toolBar = new ToolBar(headComposite, SWT.FLAT);
+ private void createCommandToolBar(Composite parent, FormToolkit toolkit) {
+ ToolBar toolBar = new ToolBar(parent, SWT.FLAT);
GridDataFactory.fillDefaults().grab(false, false).applyTo(toolBar);
toolkit.adapt(toolBar);
toolkit.paintBordersFor(toolBar);
@@ -477,7 +502,7 @@ private TreeViewer createPlanTreeViewer(Composite parent,
toolkit.paintBordersFor(rebasePlanTableComposite);
GridDataFactory.fillDefaults().grab(true, true)
.applyTo(rebasePlanTableComposite);
- GridLayoutFactory.fillDefaults().extendedMargins(2, 2, 2, 2)
+ GridLayoutFactory.fillDefaults().extendedMargins(5, 5, 5, 5)
.applyTo(rebasePlanTableComposite);
final Tree planTree = toolkit.createTree(rebasePlanTableComposite,
@@ -495,20 +520,6 @@ private TreeViewer createPlanTreeViewer(Composite parent,
return viewer;
}
- private Form createForm(Composite parent, final FormToolkit toolkit) {
- Form newForm = toolkit.createForm(parent);
-
- Image repoImage = UIIcons.REPOSITORY.createImage();
- UIUtils.hookDisposal(newForm, repoImage);
- newForm.setImage(repoImage);
- newForm.setText(UIText.RebaseInteractiveView_NoSelection);
- GridDataFactory.fillDefaults().grab(true, true).applyTo(newForm);
- toolkit.decorateFormHeading(newForm);
- GridLayoutFactory.swtDefaults().applyTo(newForm.getBody());
-
- return newForm;
- }
-
private void setupListeners() {
setupRepositoryViewSelectionChangeListener();
refreshUI();
@@ -884,13 +895,13 @@ private static String getRepositoryName(Repository repository) {
String repoName = RepositoryUtil.INSTANCE.getRepositoryName(repository);
RepositoryState state = repository.getRepositoryState();
if (state != RepositoryState.SAFE)
- return repoName + '|' + state.getDescription();
+ return repoName + " | " + state.getDescription(); //$NON-NLS-1$
else
return repoName;
}
private void showRepository(final Repository repository) {
- if (form.isDisposed())
+ if (composite.isDisposed())
return;
if (currentPlan != null)
@@ -899,7 +910,7 @@ private void showRepository(final Repository repository) {
if (isValidRepo(repository)) {
currentPlan = RebaseInteractivePlan.getPlan(repository);
currentPlan.addRebaseInteractivePlanChangeListener(this);
- form.setText(getRepositoryName(repository));
+ repoLabel.setText(getRepositoryName(repository));
} else {
currentPlan = null;
}
@@ -975,9 +986,9 @@ private void refreshUI() {
if (currentPlan == null || repo == null
|| !repo.getRepositoryState().isRebasing()) {
if (repo == null)
- form.setText(UIText.RebaseInteractiveView_NoSelection);
+ repoLabel.setText(UIText.RebaseInteractiveView_NoSelection);
else
- form.setText(getRepositoryName(repo));
+ repoLabel.setText(getRepositoryName(repo));
return;
}
IndexDiffCacheEntry entry = IndexDiffCache.INSTANCE
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/CreateBranchPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/CreateBranchPage.java
index 93c50efa87..59b23902bb 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/CreateBranchPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/CreateBranchPage.java
@@ -34,8 +34,8 @@
import org.eclipse.egit.core.internal.SafeRunnable;
import org.eclipse.egit.core.internal.Utils;
import org.eclipse.egit.core.op.CreateLocalBranchOperation;
-import org.eclipse.egit.ui.IBranchNameProvider;
import org.eclipse.egit.ui.UIUtils;
+import org.eclipse.egit.ui.api.IBranchNameProvider;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.ValidationUtils;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java
index b8c6cbad8b..bc72f5a294 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoriesView.java
@@ -178,6 +178,7 @@
import org.eclipse.ui.part.ShowInContext;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.views.WorkbenchViewerSetup;
import org.eclipse.ui.views.properties.IPropertySheetPage;
import org.eclipse.ui.views.properties.PropertySheet;
import org.eclipse.ui.views.properties.PropertySheetPage;
@@ -333,8 +334,8 @@ public void menuAboutToShow(IMenuManager m) {
Composite optionsArea = new Composite(infoArea, SWT.NONE);
optionsArea.setMenu(menu);
GridLayoutFactory.swtDefaults().numColumns(2).applyTo(optionsArea);
- GridDataFactory.swtDefaults().indent(5, 0).grab(true, true)
- .applyTo(optionsArea);
+ GridDataFactory.swtDefaults().indent(5, 0).align(SWT.FILL, SWT.CENTER)
+ .grab(true, true).applyTo(optionsArea);
final FormToolkit toolkit = new FormToolkit(emptyArea.getDisplay());
emptyArea.addDisposeListener(new DisposeListener() {
@@ -436,8 +437,10 @@ public void createPartControl(Composite aParent) {
@Override
protected CommonViewer createCommonViewerObject(Composite aParent) {
- return new RepositoriesCommonViewer(getViewSite().getId(), aParent,
+ RepositoriesCommonViewer repositoriesCommonViewer = new RepositoriesCommonViewer(getViewSite().getId(), aParent,
SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
+ WorkbenchViewerSetup.setupViewer(repositoriesCommonViewer);
+ return repositoriesCommonViewer;
}
private void setTopControl(CommonViewer viewer) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java
index 08428870e7..601eebed96 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoryTreeNode.java
@@ -332,11 +332,13 @@ public int compareTo(RepositoryTreeNode otherNode) {
// ok for positive indexes < ~2 billion
return ((StashedCommitNode) this).getIndex()
- ((StashedCommitNode) otherNode).getIndex();
- case TAG:
case ADDITIONALREF:
case REF:
return CommonUtils.REF_ASCENDING_COMPARATOR.compare((Ref) myObject,
(Ref) otherNode.getObject());
+ case TAG:
+ return CommonUtils.REF_ASCENDING_COMPARATOR.reversed()
+ .compare((Ref) myObject, (Ref) otherNode.getObject());
case REPO:
int nameCompare = CommonUtils.STRING_ASCENDING_COMPARATOR.compare(
getDirectoryContainingRepo((Repository) myObject).getName(),
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/revision/GitCompareFileRevisionEditorInput.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/revision/GitCompareFileRevisionEditorInput.java
index f847e0650e..27a12829ea 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/revision/GitCompareFileRevisionEditorInput.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/revision/GitCompareFileRevisionEditorInput.java
@@ -429,7 +429,7 @@ protected ICompareInput prepareCompareInput(IProgressMonitor monitor)
getCompareConfiguration().setRightEditable(isRightEditable(input));
ensureContentsCached(getLeftRevision(), getRightRevision(), getAncestorRevision(), monitor);
initLabels(input);
- setTitle(NLS.bind(UIText.GitCompareFileRevisionEditorInput_CompareInputTitle, new String[] { input.getName() }));
+ setTitle(NLS.bind(UIText.GitCompareFileRevisionEditorInput_CompareInputTitle, new Object[] { input.getName() }));
// The compare editor (Structure Compare) will show the diff filenames
// with their project relative path. So, no need to also show directory entries.
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/sharing/ExistingOrNewPage.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/sharing/ExistingOrNewPage.java
index 1960341f16..ffe8012590 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/sharing/ExistingOrNewPage.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/sharing/ExistingOrNewPage.java
@@ -604,18 +604,6 @@ protected void updateControls() {
prj.getName()));
break;
}
- File parent = targetTest.getParentFile();
- while (parent != null) {
- if (new File(parent, ".project").exists()) { //$NON-NLS-1$
- setErrorMessage(NLS
- .bind(UIText.ExistingOrNewPage_NestedProjectErrorMessage,
- new String[] { prj.getName(),
- targetTest.getPath(),
- parent.getPath() }));
- break;
- }
- parent = parent.getParentFile();
- }
// break after the first error
if (getErrorMessage() != null)
break;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
index 9b6fa86dc3..ac556491f1 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2011, 2022 Bernard Leach and others.
+ * Copyright (C) 2011, 2025 Bernard Leach and others.
* Copyright (C) 2015 SAP SE (Christian Georgi )
* Copyright (C) 2015 Denis Zygann
* Copyright (C) 2016 IBM (Daniel Megert )
@@ -84,9 +84,11 @@
import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.UIUtils;
+import org.eclipse.egit.ui.commit.CommitContext;
import org.eclipse.egit.ui.internal.ActionUtils;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.CompareUtils;
+import org.eclipse.egit.ui.internal.GitLabels;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.actions.ActionCommands;
@@ -110,6 +112,7 @@
import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponent;
import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponentState;
import org.eclipse.egit.ui.internal.dialogs.CommitMessageComponentStateManager;
+import org.eclipse.egit.ui.internal.dialogs.DefaultCommitContext;
import org.eclipse.egit.ui.internal.dialogs.ICommitMessageComponentNotifications;
import org.eclipse.egit.ui.internal.dialogs.SpellcheckableMessageArea;
import org.eclipse.egit.ui.internal.operations.DeletePathsOperationUI;
@@ -145,6 +148,8 @@
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.LocalSelectionTransfer;
import org.eclipse.jface.util.PropertyChangeEvent;
@@ -179,6 +184,7 @@
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.events.ListenerHandle;
+import org.eclipse.jgit.lib.BranchTrackingStatus;
import org.eclipse.jgit.lib.CommitConfig;
import org.eclipse.jgit.lib.CommitConfig.CleanupMode;
import org.eclipse.jgit.lib.Constants;
@@ -191,6 +197,7 @@
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.util.StringUtils;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.custom.VerifyKeyListener;
@@ -235,6 +242,7 @@
import org.eclipse.ui.IPartService;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchCommandConstants;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
@@ -245,10 +253,10 @@
import org.eclipse.ui.actions.ActionFactory.IWorkbenchAction;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
-import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.menus.IMenuService;
import org.eclipse.ui.operations.UndoRedoActionGroup;
import org.eclipse.ui.part.IShowInSource;
import org.eclipse.ui.part.IShowInTarget;
@@ -291,7 +299,9 @@ public class StagingView extends ViewPart
private FormToolkit toolkit;
- private Form form;
+ private Composite composite;
+
+ private CLabel repoLabel;
private RepositoryNode titleNode;
@@ -315,6 +325,8 @@ public class StagingView extends ViewPart
private Text filterText;
+ private ControlContribution filterContribution;
+
/** Remember compiled pattern of the current filter string for performance. */
private Pattern filterPattern;
@@ -369,6 +381,8 @@ public class StagingView extends ViewPart
private IAction compareModeAction;
+ private IWorkbenchAction reuseCompareEditorAction;
+
private IWorkbenchAction switchRepositoriesAction;
/** The currently set repository, even if it is bare. */
@@ -767,8 +781,18 @@ public void indexDiffChanged(Repository repository,
private boolean disposed;
+ private CommitContext commitContext;
+
+ @Override
+ public T getAdapter(Class adapter) {
+ if (adapter == CommitContext.class) {
+ return adapter.cast(commitContext);
+ }
+ return super.getAdapter(adapter);
+ }
+
private Image getImage(ImageDescriptor descriptor) {
- return (Image) this.resources.get(descriptor);
+ return this.resources.get(descriptor);
}
private void createPersonLabel(Composite parent, ImageDescriptor image,
@@ -790,7 +814,8 @@ public void createPartControl(final Composite parent) {
new RepositoryTreeNodeLabelProvider(),
PlatformUI.getWorkbench().getDecoratorManager());
titleLabelProvider.addListener(e -> {
- if (titleNode != null && form != null && !form.isDisposed()) {
+ if (titleNode != null && repoLabel != null
+ && !repoLabel.isDisposed()) {
updateTitle(false);
}
});
@@ -809,7 +834,7 @@ public void widgetDisposed(DisposeEvent e) {
}
});
- form = toolkit.createForm(parent);
+ composite = new Composite(parent, SWT.NONE);
parent.addControlListener(new ControlListener() {
private int[] defaultWeights = { 1, 1 };
@@ -834,13 +859,16 @@ public void controlMoved(ControlEvent e) {
// ignore
}
});
- form.setImage(getImage(UIIcons.REPOSITORY));
- form.setText(UIText.StagingView_NoSelectionTitle);
- GridDataFactory.fillDefaults().grab(true, true).applyTo(form);
- toolkit.decorateFormHeading(form);
- GridLayoutFactory.swtDefaults().applyTo(form.getBody());
+ GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
+ GridLayoutFactory.swtDefaults().applyTo(composite);
+
+ repoLabel = new CLabel(composite, SWT.NONE);
+ repoLabel.setImage(getImage(UIIcons.REPOSITORY));
+ repoLabel.setText(UIText.StagingView_NoSelectionTitle);
+ GridDataFactory.fillDefaults().grab(true, false)
+ .applyTo(repoLabel);
- mainSashForm = new SashForm(form.getBody(), getMainSashFormOrientation());
+ mainSashForm = new SashForm(composite, getMainSashFormOrientation());
saveSashFormOrientationOnDisposal(mainSashForm, MAIN_SASH_FORM_ORIENTATION_VERTICAL);
saveSashFormWeightsOnDisposal(mainSashForm,
HORIZONTAL_SASH_FORM_WEIGHT);
@@ -904,6 +932,7 @@ public void run() {
unstagedSection = toolkit.createSection(stagingSashForm,
ExpandableComposite.SHORT_TITLE_BAR);
+ unstagedSection.setFont(stagingSashForm.getFont());
unstagedSection.clientVerticalSpacing = 0;
unstagedSection.setLayoutData(
@@ -933,6 +962,7 @@ public void run() {
rebaseSection = toolkit.createSection(rebaseAndCommitComposite,
ExpandableComposite.SHORT_TITLE_BAR);
+ rebaseSection.setFont(rebaseAndCommitComposite.getFont());
rebaseSection.clientVerticalSpacing = 0;
rebaseSection.setText(UIText.StagingView_RebaseLabel);
@@ -983,6 +1013,7 @@ public void widgetSelected(SelectionEvent e) {
commitMessageSection = toolkit.createSection(rebaseAndCommitComposite,
ExpandableComposite.SHORT_TITLE_BAR);
+ commitMessageSection.setFont(rebaseAndCommitComposite.getFont());
commitMessageSection.clientVerticalSpacing = 0;
commitMessageSection.setText(UIText.StagingView_CommitMessage);
commitMessageSection.setLayoutData(GridDataFactory.fillDefaults()
@@ -996,6 +1027,19 @@ public void widgetSelected(SelectionEvent e) {
ToolBarManager commitMessageToolBarManager = new ToolBarManager(
SWT.FLAT | SWT.HORIZONTAL);
+ IDocumentListener updatePreview = new IDocumentListener() {
+
+ @Override
+ public void documentChanged(DocumentEvent event) {
+ previewer.setText(commitMessageComponent.getRepository(),
+ commitMessageComponent.getCommitMessage());
+ }
+
+ @Override
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ // Nothing
+ }
+ };
previewAction = new Action(UIText.StagingView_Preview_Commit_Message,
IAction.AS_CHECK_BOX) {
@@ -1009,7 +1053,11 @@ public void run() {
previewer
.setText(commitMessageComponent.getRepository(),
commitMessageComponent.getCommitMessage());
+ commitMessageText.getDocument()
+ .addDocumentListener(updatePreview);
} else {
+ commitMessageText.getDocument()
+ .removeDocumentListener(updatePreview);
previewLayout.topControl = commitMessageText;
commitMessageSection
.setText(UIText.StagingView_CommitMessage);
@@ -1024,7 +1072,8 @@ public void run() {
};
previewAction.setImageDescriptor(UIIcons.ELCL16_PREVIEW);
commitMessageToolBarManager.add(previewAction);
- commitMessageToolBarManager.add(new Separator());
+ commitMessageToolBarManager
+ .add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
amendPreviousCommitAction = new Action(
UIText.StagingView_Ammend_Previous_Commit, IAction.AS_CHECK_BOX) {
@@ -1075,6 +1124,9 @@ public void run() {
addChangeIdAction.setImageDescriptor(UIIcons.GERRIT);
commitMessageToolBarManager.add(addChangeIdAction);
+ addContributions(commitMessageToolBarManager,
+ commitMessageToolbarComposite);
+
commitMessageToolBarManager
.createControl(commitMessageToolbarComposite);
@@ -1138,6 +1190,13 @@ protected IHandlerService getHandlerService() {
commitMessageText.getTextWidget(),
UIText.CommitDialog_ContentAssist);
+ commitContext = new DefaultCommitContext(commitMessageText) {
+ @Override
+ public Repository getRepository() {
+ return getCurrentRepository();
+ }
+ };
+
commitMessagePreview = new Composite(commitMessageTextComposite,
SWT.NONE);
commitMessagePreview.setLayout(new FillLayout());
@@ -1148,23 +1207,23 @@ protected IHandlerService getHandlerService() {
previewLayout.topControl = commitMessageText;
- Composite composite = toolkit.createComposite(commitMessageComposite);
- toolkit.paintBordersFor(composite);
- GridDataFactory.fillDefaults().grab(true, false).applyTo(composite);
+ Composite personComposite = toolkit.createComposite(commitMessageComposite);
+ toolkit.paintBordersFor(personComposite);
+ GridDataFactory.fillDefaults().grab(true, false).applyTo(personComposite);
GridLayoutFactory.swtDefaults().margins(1, 2).numColumns(3)
- .spacing(1, LayoutConstants.getSpacing().y).applyTo(composite);
+ .spacing(1, LayoutConstants.getSpacing().y).applyTo(personComposite);
- createPersonLabel(composite, UIIcons.ELCL16_AUTHOR,
+ createPersonLabel(personComposite, UIIcons.ELCL16_AUTHOR,
UIText.StagingView_Author);
- authorText = toolkit.createText(composite, null);
+ authorText = toolkit.createText(personComposite, null);
authorText.setData(FormToolkit.KEY_DRAW_BORDER,
FormToolkit.TEXT_BORDER);
authorText.setLayoutData(GridDataFactory.fillDefaults().indent(5, 0)
.grab(true, false).align(SWT.FILL, SWT.CENTER).create());
- createPersonLabel(composite, UIIcons.ELCL16_COMMITTER,
+ createPersonLabel(personComposite, UIIcons.ELCL16_COMMITTER,
UIText.StagingView_Committer);
- committerText = toolkit.createText(composite, null);
+ committerText = toolkit.createText(personComposite, null);
committerText.setData(FormToolkit.KEY_DRAW_BORDER,
FormToolkit.TEXT_BORDER);
committerText.setLayoutData(GridDataFactory.fillDefaults().indent(5, 0)
@@ -1276,6 +1335,7 @@ public void widgetSelected(SelectionEvent e) {
stagedSection = toolkit.createSection(stagingSashForm,
ExpandableComposite.SHORT_TITLE_BAR);
+ stagedSection.setFont(stagingSashForm.getFont());
stagedSection.clientVerticalSpacing = 0;
createStagedToolBarComposite();
@@ -1453,25 +1513,85 @@ else if (element instanceof StagingFolderEntry)
service.showBusyForFamily(org.eclipse.egit.core.JobFamilies.INDEX_DIFF_CACHE_UPDATE);
}
+ private void addContributions(ToolBarManager toolBarManager,
+ Composite container) {
+ IMenuService menuService = getSite().getService(IMenuService.class);
+ if (menuService != null) {
+ String toolbarUri = "toolbar:" //$NON-NLS-1$
+ + CommitContext.COMMIT_MSG_TOOLBAR_ID;
+ menuService.populateContributionManager(toolBarManager, toolbarUri);
+ container.addDisposeListener(event -> {
+ menuService.releaseContributions(toolBarManager);
+ toolBarManager.dispose();
+ });
+ }
+ }
+
private void updateTitle(boolean force) {
ViewerLabel label = titleLabels.computeIfAbsent(
titleNode.getRepository().getDirectory(),
r -> new ViewerLabel(null, null));
if (force) {
- if (label.getImage() != null) {
- form.setImage(label.getImage());
- }
if (!StringUtils.isEmptyOrNull(label.getText())) {
- form.setText(label.getText());
+ updateRepoLabel(label.getText(),
+ label.getImage() != null ? label.getImage()
+ : getImage(UIIcons.REPOSITORY));
}
}
titleLabelProvider.updateLabel(label, titleNode);
- if (label.hasNewImage()) {
- form.setImage(label.getImage());
+ if (label.hasNewText() || label.hasNewImage()) {
+ updateRepoLabel(label.getText(),
+ label.getImage() != null ? label.getImage()
+ : getImage(UIIcons.REPOSITORY));
+ }
+ }
+
+ private void updateRepoLabel(String text, Image image) {
+ if (repoLabel != null && !repoLabel.isDisposed()) {
+ repoLabel.setText(text);
+ repoLabel.setImage(image);
+ repoLabel.setToolTipText(buildRepoTooltip());
+ repoLabel.requestLayout();
+ }
+ }
+
+ private String buildRepoTooltip() {
+ if (titleNode == null) {
+ return null;
}
- if (label.hasNewText()) {
- form.setText(label.getText());
+ Repository repository = titleNode.getRepository();
+ StringBuilder sb = new StringBuilder();
+ sb.append(UIText.StagingView_RepoTooltipRepository).append(": ") //$NON-NLS-1$
+ .append(RepositoryUtil.INSTANCE
+ .getRepositoryName(repository));
+ sb.append('\n');
+ sb.append(UIText.StagingView_RepoTooltipPath).append(": ") //$NON-NLS-1$
+ .append(repository.getDirectory().getAbsolutePath());
+ try {
+ String branch = RepositoryUtil.INSTANCE
+ .getShortBranch(repository);
+ if (branch != null) {
+ sb.append('\n');
+ sb.append(UIText.StagingView_RepoTooltipBranch)
+ .append(": ") //$NON-NLS-1$
+ .append(branch);
+ BranchTrackingStatus trackingStatus = BranchTrackingStatus
+ .of(repository, branch);
+ if (trackingStatus != null) {
+ int ahead = trackingStatus.getAheadCount();
+ int behind = trackingStatus.getBehindCount();
+ if (ahead != 0 || behind != 0) {
+ sb.append('\n');
+ sb.append(GitLabels
+ .formatBranchTrackingStatus(
+ trackingStatus));
+ }
+ }
+ }
+ } catch (IOException e) {
+ // ignore
}
+ return sb.toString();
}
private void setCommentCharTooltip() {
@@ -2090,9 +2210,13 @@ private void initPresentation() {
private void updateToolbar() {
- ControlContribution controlContribution = new ControlContribution(
+ filterContribution = new ControlContribution(
"StagingView.searchText") { //$NON-NLS-1$
+ private String lastFilter;
+
+ private Point lastFilterSelection;
+
@Override
protected Control createControl(Composite parent) {
Composite toolbarComposite = new Composite(parent,
@@ -2104,9 +2228,9 @@ protected Control createControl(Composite parent) {
headLayout.marginWidth = 0;
toolbarComposite.setLayout(headLayout);
- filterText = new Text(toolbarComposite, SWT.SEARCH
- | SWT.ICON_CANCEL | SWT.ICON_SEARCH);
- filterText.setMessage(UIText.StagingView_Find);
+ filterText = new Text(toolbarComposite,
+ SWT.SEARCH | SWT.ICON_CANCEL);
+ filterText.setMessage(UIText.StagingView_Filter);
GridData data = new GridData(SWT.LEFT, SWT.TOP, true, false);
data.minimumWidth = 150;
filterText.setLayoutData(data);
@@ -2117,14 +2241,79 @@ protected Control createControl(Composite parent) {
filterText.getDisplay().timerExec(200,
searchThread::start);
});
+ if (lastFilter != null && !lastFilter.isEmpty()) {
+ filterText.setText(lastFilter);
+ lastFilter = null;
+ if (lastFilterSelection != null) {
+ filterText.setSelection(lastFilterSelection);
+ lastFilterSelection = null;
+ }
+ }
return toolbarComposite;
}
+
+ @Override
+ public void setVisible(boolean visible) {
+ boolean change = visible != isVisible();
+ if (filterText != null && change && !visible) {
+ String current = filterText.getText();
+ lastFilterSelection = filterText.getSelection();
+ lastFilter = current;
+ if (current != null && !current.isEmpty()) {
+ filterText.setText(""); //$NON-NLS-1$
+ }
+ }
+ super.setVisible(visible);
+ }
};
+ boolean showFilter = getPreferenceStore()
+ .getBoolean(UIPreferences.STAGING_VIEW_SHOW_FILTER);
+ filterContribution.setVisible(showFilter);
IActionBars actionBars = getViewSite().getActionBars();
IToolBarManager toolbar = actionBars.getToolBarManager();
+ IMenuManager dropdownMenu = actionBars.getMenuManager();
+
+ toolbar.removeAll();
+ dropdownMenu.removeAll();
- toolbar.add(controlContribution);
+ toolbar.add(filterContribution);
+
+ Action showFilterAction = new Action(
+ UIText.StagingView_Filter_actionLabel,
+ IAction.AS_CHECK_BOX) {
+
+ @Override
+ public void run() {
+ boolean checked = isChecked();
+ getPreferenceStore().setValue(
+ UIPreferences.STAGING_VIEW_SHOW_FILTER, checked);
+ filterContribution.setVisible(checked);
+ toolbar.update(true);
+ if (checked && filterText != null && !filterText.isDisposed()) {
+ filterText.setFocus();
+ }
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ super.setChecked(checked);
+ if (checked) {
+ setToolTipText(
+ UIText.StagingView_HideFilterTooltip);
+ } else {
+ setToolTipText(
+ UIText.StagingView_ShowFilterTooltip);
+ }
+ }
+ };
+ showFilterAction.setActionDefinitionId(
+ IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE);
+ showFilterAction.setImageDescriptor(UIIcons.ELCL16_FILTER);
+ showFilterAction.setChecked(showFilter);
+ toolbar.add(showFilterAction);
+ actionBars.setGlobalActionHandler(ActionFactory.FIND.getId(),
+ showFilterAction);
refreshAction = new Action(UIText.StagingView_Refresh, IAction.AS_PUSH_BUTTON) {
@Override
@@ -2247,13 +2436,14 @@ public void run() {
fileNameModeAction.setChecked(getPreferenceStore().getBoolean(
UIPreferences.STAGING_VIEW_FILENAME_MODE));
- IMenuManager dropdownMenu = actionBars.getMenuManager();
dropdownMenu.add(presentationAction);
dropdownMenu.add(new Separator());
dropdownMenu.add(openNewCommitsAction);
dropdownMenu.add(columnLayoutAction);
dropdownMenu.add(fileNameModeAction);
dropdownMenu.add(compareModeAction);
+ reuseCompareEditorAction = new CompareUtils.ReuseCompareEditorAction();
+ dropdownMenu.add(reuseCompareEditorAction);
actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), new GlobalDeleteActionHandler());
@@ -2323,8 +2513,8 @@ private boolean isExpandAllowed(boolean staged) {
return contentProvider.getCount() <= getMaxLimitForListMode();
}
- private TreeViewer createTree(Composite composite) {
- Tree tree = toolkit.createTree(composite, SWT.FULL_SELECTION
+ private TreeViewer createTree(Composite parent) {
+ Tree tree = toolkit.createTree(parent, SWT.FULL_SELECTION
| SWT.MULTI);
TreeViewer treeViewer = new TreeViewer(tree);
treeViewer.setUseHashlookup(true);
@@ -2405,7 +2595,7 @@ private TreeViewer createViewer(Composite parent, boolean unstaged,
Tree tree = viewer.getTree();
// Paint an indicator at the end of the column.
tree.addListener(SWT.MeasureItem, event -> {
- Object obj = ((TreeItem) event.item).getData();
+ Object obj = event.item.getData();
if (obj instanceof StagingEntry) {
StagingEntry entry = (StagingEntry) obj;
String text = getConflictText(entry);
@@ -2429,7 +2619,7 @@ private TreeViewer createViewer(Composite parent, boolean unstaged,
// middle of the label text in the hover.
return;
}
- Object obj = ((TreeItem) event.item).getData();
+ Object obj = event.item.getData();
if (obj instanceof StagingEntry) {
StagingEntry entry = (StagingEntry) obj;
String text = getConflictText(entry);
@@ -3539,7 +3729,7 @@ public void run() {
if (files.isEmpty()) {
return;
}
- if (!CommandConfirmation.confirmCheckout(form.getShell(), repo)) {
+ if (!CommandConfirmation.confirmCheckout(composite.getShell(), repo)) {
return;
}
DiscardChangesOperation operation = new DiscardChangesOperation(
@@ -4065,11 +4255,12 @@ private void clearRepository(@Nullable Repository repository) {
refreshAction.setEnabled(false);
updateSectionText();
titleNode = null;
- form.setImage(getImage(UIIcons.REPOSITORY));
if (repository != null && repository.isBare()) {
- form.setText(UIText.StagingView_BareRepoSelection);
+ updateRepoLabel(UIText.StagingView_BareRepoSelection,
+ getImage(UIIcons.REPOSITORY));
} else {
- form.setText(UIText.StagingView_NoSelectionTitle);
+ updateRepoLabel(UIText.StagingView_NoSelectionTitle,
+ getImage(UIIcons.REPOSITORY));
}
updateIgnoreErrorsButtonVisibility();
updateRebaseButtonVisibility(false);
@@ -4917,6 +5108,10 @@ public void dispose() {
presentationAction.dispose();
presentationAction = null;
}
+ if (reuseCompareEditorAction != null) {
+ reuseCompareEditorAction.dispose();
+ reuseCompareEditorAction = null;
+ }
getPreferenceStore().removePropertyChangeListener(uiPrefsListener);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashApplyResultNotification.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashApplyResultNotification.java
new file mode 100644
index 0000000000..f1294b6e4c
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashApplyResultNotification.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (C) 2026 vogella GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.stash;
+
+import org.eclipse.egit.core.RepositoryUtil;
+import org.eclipse.egit.core.internal.Utils;
+import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.notifications.NotificationPopup;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * A non-blocking, auto-dismissing notification shown after a successful stash
+ * apply operation.
+ */
+public class StashApplyResultNotification {
+
+ /**
+ * Opens a notification popup for a successful stash apply.
+ *
+ * @param shell
+ * the parent shell
+ * @param repository
+ * the repository
+ * @param commit
+ * the stashed commit that was applied
+ */
+ public static void open(Shell shell, Repository repository,
+ RevCommit commit) {
+ NotificationPopup.forShell(shell)
+ .title(UIText.StashApplyResultNotification_Title, true)
+ .content(parent -> {
+ GridLayoutFactory.fillDefaults().margins(4, 0)
+ .applyTo(parent);
+ Label body = new Label(parent, SWT.WRAP);
+ body.setText(NLS.bind(
+ UIText.StashApplyResultNotification_Message,
+ Utils.getShortObjectId(commit),
+ RepositoryUtil.INSTANCE
+ .getRepositoryName(repository)));
+ GridDataFactory.fillDefaults().grab(true, false)
+ .hint(280, SWT.DEFAULT).applyTo(body);
+ return parent;
+ })
+ .open();
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashCreateUI.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashCreateUI.java
index 829d35f516..5aac5fbcf6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashCreateUI.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/stash/StashCreateUI.java
@@ -19,6 +19,8 @@
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.egit.core.RepositoryUtil;
+import org.eclipse.egit.core.internal.Utils;
import org.eclipse.egit.core.op.StashCreateOperation;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.JobFamilies;
@@ -28,8 +30,12 @@
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.notifications.NotificationPopup;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.window.Window;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.swt.SWT;
@@ -83,6 +89,32 @@ public IStatus runInWorkspace(IProgressMonitor monitor) {
RevCommit commit = op.getCommit();
if (commit == null) {
showNoChangesToStash();
+ } else if (Activator.getDefault().getPreferenceStore()
+ .getBoolean(UIPreferences.STASH_APPLY_SHOW_NOTIFICATION)) {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(() -> {
+ Shell activeShell = PlatformUI.getWorkbench()
+ .getActiveWorkbenchWindow().getShell();
+ NotificationPopup.forShell(activeShell)
+ .title(UIText.StashCreateResultNotification_Title,
+ true)
+ .content(parent -> {
+ GridLayoutFactory.fillDefaults()
+ .margins(4, 0).applyTo(parent);
+ Label body = new Label(parent, SWT.WRAP);
+ body.setText(NLS.bind(
+ UIText.StashCreateResultNotification_Message,
+ Utils.getShortObjectId(commit),
+ RepositoryUtil.INSTANCE
+ .getRepositoryName(
+ repo)));
+ GridDataFactory.fillDefaults()
+ .grab(true, false)
+ .hint(280, SWT.DEFAULT)
+ .applyTo(body);
+ return parent;
+ })
+ .open();
+ });
}
} catch (CoreException e) {
Activator
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties
index a2b10cc17d..ae992ca7dc 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/uitext.properties
@@ -143,7 +143,6 @@ ExistingOrNewPage_HeaderLocation=Location
ExistingOrNewPage_HeaderProject=Project
ExistingOrNewPage_HeaderRepository=Repository
ExistingOrNewPage_InternalModeCheckbox=&Use or create repository in parent folder of project
-ExistingOrNewPage_NestedProjectErrorMessage=Cannot move project {0} to target location {1}, as this location overlaps with location {2}, which contains a .project file
ExistingOrNewPage_NewLocationTargetHeader=Target Location
ExistingOrNewPage_NoRepositorySelectedMessage=No repository selected
ExistingOrNewPage_ProjectNameColumnHeader=Project
@@ -294,6 +293,8 @@ GitPreferenceRoot_lfsSupportCaptionNotAvailable=LFS support (not installed)
GitPreferenceRoot_lfsSupportInstall=Enable &LFS support globally (for the current user)
GitPreferenceRoot_lfsSupportSuccessMessage=LFS support has been installed for the current user.
GitPreferenceRoot_lfsSupportSuccessTitle=LFS configured
+GitPreferenceRoot_clipboardHeader=Monitor clipboard
+GitPreferenceRoot_clipboardLabel=Always check clipboard content for possible git repository URLs
GitServersPreferencePage_AddLabel=A&dd
GitServersPreferencePage_Description=Enter host name patterns for Git servers.
GitServersPreferencePage_PatternTitle=Host Name Pattern
@@ -912,7 +913,7 @@ CommitDialog_Path=Path
CommitDialog_Title=Commit Changes to {0}
CommitDialog_IgnoreErrors=Ignore warnings and errors
CommitDialog_MessageErrors=Fix warnings/errors before you commit changes or explicitly ignore them
-CommitDialog_WrongTypeOfCommitMessageProvider=The CommitMessageProvider extension {0} contributed by {1} has the wrong type (it must implement org.eclipse.egit.ui.ICommitMessageProvider)
+CommitDialog_WrongTypeOfCommitMessageProvider=The CommitMessageProvider extension {0} contributed by {1} has the wrong type (it must implement org.eclipse.egit.ui.api.ICommitMessageProvider)
CommitDialog_ErrorCreatingCommitMessageProvider=The CommitMessageProvider extension {0} contributed by {1} could not be created
CommitDialog_CaretPositionOutOfBounds=The ICommitMessageProvider2 implementation {0} provided the caret position {1}, which exceeds the length of the commit message or is negative. The caret position is ignored.
CommitDialog_IgnoreCaretPosition=Found multiple implementations of ICommitMessageProvider2. Ignoring caret positioning for {0}.
@@ -1020,6 +1021,11 @@ CreateRepositoryPage_ReadDefaultBranchFailed=Reading git configuration "init.def
PushResultDialog_title=Push Results: {0}
PushResultDialog_label=Pushed to {0}
PushResultDialog_label_failed=Failed pushing to {0}
+PushResultNotification_Title=Pushed to {0}
+PushResultNotification_UpToDate=Everything up to date.
+PushResultNotification_RefsUpdated={0} ref(s) pushed.
+PushResultNotification_PushRejected=Push rejected.
+PushResultNotification_Details=Details...
PushResultDialog_ConfigureButton=C&onfigure...
PushResultTable_MessageText=Message Details
PushResultTable_PrePushHookOutput=Output from the ''pre-push'' hook:\n{0}{1}--------\n
@@ -1124,6 +1130,14 @@ FetchResultDialog_labelEmptyResult=No ref to fetch from {0} - everything up to d
FetchResultDialog_labelNonEmptyResult=Fetched from {0}.
FetchResultDialog_title=Fetch Results: {0}
FetchResultDialog_CloseButton=C&lose
+FetchResultNotification_Title=Fetched from {0}
+FetchResultNotification_UpToDate=Everything up to date.
+FetchResultNotification_RefsUpdated={0} ref(s) updated.
+FetchResultNotification_Details=Details...
+StashApplyResultNotification_Title=Stash Applied
+StashApplyResultNotification_Message=Stash {0} was successfully applied to {1}.
+StashCreateResultNotification_Title=Stash Created
+StashCreateResultNotification_Message=Changes in {1} were stashed as {0}.
FetchResultTable_addingChildren=Adding Children
FetchResultTable_counterCommits=\ ({0})
@@ -1371,8 +1385,8 @@ DecoratorPreferencesPage_fileFormatLabel=&Files:
DecoratorPreferencesPage_folderFormatLabel=F&olders:
DecoratorPreferencesPage_projectFormatLabel=&Projects:
DecoratorPreferencesPage_submoduleFormatLabel=&Submodules:
-DecoratorPreferencesPage_labelDecorationsLink=See ''{0}'' to enable or disable Git decorations.
-DecoratorPreferencesPage_colorsAndFontsLink=See ''{0}'' to configure the font and color decorations.
+DecoratorPreferencesPage_labelDecorationsLink=See {0} to enable or disable Git decorations.
+DecoratorPreferencesPage_colorsAndFontsLink=See {0} to configure the font and color decorations.
DecoratorPreferencesPage_generalTabFolder=&General
DecoratorPreferencesPage_bindingResourceName=Name of the resource being decorated
DecoratorPreferencesPage_bindingBranchName=Current branch of the repository
@@ -1497,7 +1511,10 @@ DialogsPreferencePage_HideConfirmationGroupHeader=Show confirmation dialogs
DialogsPreferencePage_ShowDeleteRepoGroup=Deletion of non-empty repository groups in the repositories view
DialogsPreferencePage_ShowInfoGroupHeader=Show result dialogs after git remote operations
DialogsPreferencePage_ShowFetchInfoDialog=&Fetch Result Dialog
+DialogsPreferencePage_FetchShowNotification=Use ¬ification instead of dialog for fetch result
+DialogsPreferencePage_StashApplyShowNotification=Show ¬ification after successful stash apply
DialogsPreferencePage_ShowPushInfoDialog=&Push Result Dialog
+DialogsPreferencePage_PushShowNotification=Use notificatio&n instead of dialog for push result
DialogsPreferencePage_ShowTooltip=If unchecked, the result dialog will not be shown automatically. It will still be available via the progress view.
DialogsPreferencePage_HideWarningGroupHeader=Log warnings
DialogsPreferencePage_HomeDirWarning=&Home directory warning (Windows only)
@@ -1516,7 +1533,7 @@ DiffEditor_OutlineShowCompactTreeTooltip=Show nested folders
DiffEditor_OutlineTreeToggle=Toggle Presentation
DiffEditor_QuickOutlineAction=&Quick Outline
DiffEditor_QuickOutlineFilterHint=Filter...
-DiffEditor_QuickOutlineFilterDescription=Filter by entering search string; Close with ESC
+DiffEditor_QuickOutlineFilterDescription=Filter by entering search string; close with ESC
DiffEditorInput_Title1=Diff {0} ({1})
DiffEditorInput_Title2=Diff {0}..{1} ({2})
DiffEditorInput_Tooltip1=Changes of commit {0} in git repository ''{1}''
@@ -2136,6 +2153,9 @@ StagingView_headCommitChanged=WARNING: head commit changed in the meantime
StagingView_noStagedFiles=There are no staged files.
StagingView_BareRepoSelection=Bare Repository Selected
StagingView_NoSelectionTitle=No Repository Selected
+StagingView_RepoTooltipRepository=Repository
+StagingView_RepoTooltipPath=Path
+StagingView_RepoTooltipBranch=Branch
StagingView_CompareMode=Compare Mode
StagingView_OpenNewCommits=Open New Commits
StagingView_ColumnLayout=Column Layout
@@ -2168,7 +2188,10 @@ StagingView_Presentation=Presentation
StagingView_List=List
StagingView_Tree=Tree
StagingView_CompactTree=Compact Tree
-StagingView_Find=Filter files
+StagingView_Filter=Filter files
+StagingView_Filter_actionLabel=&Filter Toolbar
+StagingView_ShowFilterTooltip=Show Filter
+StagingView_HideFilterTooltip=Hide Filter
StagingView_MergeTool=Merge Tool
StagingView_AddJob=Adding files to index...
StagingView_RemoveJob=Removing files from index...
diff --git a/org.eclipse.egit/META-INF/MANIFEST.MF b/org.eclipse.egit/META-INF/MANIFEST.MF
index 56f81676d4..310e1797b0 100644
--- a/org.eclipse.egit/META-INF/MANIFEST.MF
+++ b/org.eclipse.egit/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.egit;singleton:=true
-Bundle-Version: 7.2.1.qualifier
+Bundle-Version: 7.7.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-ActivationPolicy: lazy
diff --git a/org.eclipse.egit/egit.svg b/org.eclipse.egit/egit.svg
index 22b029edb6..3c5023cdd2 100644
--- a/org.eclipse.egit/egit.svg
+++ b/org.eclipse.egit/egit.svg
@@ -2,14 +2,6 @@
+ id="path3841" />