package zielu.gittoolbox.ui.statusBar; import com.intellij.ide.ui.UISettings; import com.intellij.ide.ui.UISettingsListener; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.FileEditorManagerEvent; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.StatusBarWidget; import com.intellij.openapi.wm.impl.status.EditorBasedWidget; import com.intellij.util.Consumer; import git4idea.GitVcs; import git4idea.branch.GitBranchUtil; import git4idea.repo.GitRepository; import java.awt.event.MouseEvent; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import zielu.gittoolbox.ConfigNotifier; import zielu.gittoolbox.GitToolBoxConfig; import zielu.gittoolbox.GitToolBoxProject; import zielu.gittoolbox.ResBundle; import zielu.gittoolbox.cache.PerRepoInfoCache; import zielu.gittoolbox.cache.PerRepoStatusCacheListener; import zielu.gittoolbox.cache.RepoInfo; import zielu.gittoolbox.status.GitAheadBehindCount; import zielu.gittoolbox.ui.StatusText; import zielu.gittoolbox.ui.util.AppUtil; public class GitStatusWidget extends EditorBasedWidget implements StatusBarWidget.Multiframe, StatusBarWidget.MultipleTextValuesPresentation { public static final String id = GitStatusWidget.class.getName(); private final AtomicBoolean opened = new AtomicBoolean(); private final StatusToolTip myToolTip; private final RootActions myRootActions; private String myText = ""; private boolean myVisible = true; private GitStatusWidget(@NotNull Project project) { super(project); myToolTip = new StatusToolTip(project); myRootActions = new RootActions(project); myConnection.subscribe(PerRepoInfoCache.CACHE_CHANGE, new PerRepoStatusCacheListener() { @Override public void stateChanged(@NotNull RepoInfo info, @NotNull GitRepository repository) { onCacheChange(info, repository); } }); myConnection.subscribe(ConfigNotifier.CONFIG_TOPIC, new ConfigNotifier.Adapter() { @Override public void configChanged(GitToolBoxConfig config) { runUpdateLater(); } }); myConnection.subscribe(UISettingsListener.TOPIC, uiSettings -> AppUtil.invokeLaterIfNeeded(this::updateStatusBar)); } private void onCacheChange(@NotNull final RepoInfo info, @NotNull final GitRepository repository) { AppUtil.invokeLaterIfNeeded(() -> { if (opened.get() && repository.equals(GitBranchUtil.getCurrentRepository(myProject))) { update(repository, info.count); updateStatusBar(); } }); } private void runUpdateLater() { AppUtil.invokeLaterIfNeeded(() -> { if (opened.get()) { runUpdate(); } }); } public static GitStatusWidget create(@NotNull Project project) { return new GitStatusWidget(project); } void setVisible(boolean visible) { myVisible = visible; runUpdateLater(); } @Override public StatusBarWidget copy() { return new GitStatusWidget(myProject); } @NotNull @Override public String ID() { return id; } @Nullable @Override public WidgetPresentation getPresentation(@NotNull PlatformType platformType) { return this; } @Nullable @Override public ListPopup getPopupStep() { if (myRootActions.update()) { return new StatusActionGroupPopup(ResBundle.getString("statusBar.menu.title"), myRootActions, myProject, Condition.TRUE); } else { return null; } } @Nullable @Override public String getSelectedValue() { return myText; } @NotNull @Override public String getMaxValue() { return ""; } @Nullable @Override public String getTooltipText() { return myToolTip.getText(); } @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { runUpdate(); } @Override public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) { runUpdate(); } @Override public void selectionChanged(@NotNull FileEditorManagerEvent event) { runUpdate(); } private void updateStatusBar() { if (myStatusBar != null) { myStatusBar.updateWidget(ID()); } } private void empty() { myToolTip.clear(); myText = ""; } private void updateData(@NotNull GitRepository repository, @Nullable GitAheadBehindCount aheadBehind) { myToolTip.update(repository, aheadBehind); if (aheadBehind != null) { String statusText = StatusText.format(aheadBehind); myText = ResBundle.getString("status.prefix") + " " + statusText; } else { myText = ResBundle.getString("status.prefix") + " " + ResBundle.getString("git.na"); } } private void runUpdate() { GitVcs git = GitVcs.getInstance(myProject); if (git != null) { GitRepository repository = GitBranchUtil.getCurrentRepository(myProject); GitAheadBehindCount aheadBehind = null; if (repository != null) { GitToolBoxProject toolBox = GitToolBoxProject.getInstance(myProject); aheadBehind = toolBox.perRepoStatusCache().getInfo(repository).count; } update(repository, aheadBehind); } else { empty(); } updateStatusBar(); } private void update(@Nullable GitRepository repository, @Nullable GitAheadBehindCount aheadBehind) { if (myVisible) { if (repository != null) { updateData(repository, aheadBehind); } else { empty(); } } else { empty(); } } @Nullable @Override public Consumer<MouseEvent> getClickConsumer() { return null; } public void installed() { opened.compareAndSet(false, true); } public void uninstalled() { opened.compareAndSet(true, false); } }