/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.dvcs.ui;
import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.repo.VcsRepositoryManager;
import com.intellij.dvcs.repo.VcsRepositoryMappingListener;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
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.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.StatusBarWidget;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.status.EditorBasedWidget;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import consulo.annotations.RequiredDispatchThread;
import java.awt.event.MouseEvent;
public abstract class DvcsStatusWidget<T extends Repository> extends EditorBasedWidget
implements StatusBarWidget.MultipleTextValuesPresentation, StatusBarWidget.Multiframe
{
protected static final Logger LOG = Logger.getInstance(DvcsStatusWidget.class);
private static final String MAX_STRING = "VCS: Rebasing feature-12345";
@NotNull private final String myPrefix;
@Nullable private String myText;
@Nullable private String myTooltip;
protected DvcsStatusWidget(@NotNull Project project, @NotNull String prefix) {
super(project);
myPrefix = prefix;
}
@Nullable
protected abstract T guessCurrentRepository(@NotNull Project project);
@NotNull
protected abstract String getFullBranchName(@NotNull T repository);
protected abstract boolean isMultiRoot(@NotNull Project project);
@NotNull
protected abstract ListPopup getPopup(@NotNull Project project, @NotNull T repository);
protected abstract void subscribeToRepoChangeEvents(@NotNull Project project);
protected abstract void rememberRecentRoot(@NotNull String path);
public void activate() {
Project project = getProject();
if (project != null) {
installWidgetToStatusBar(project, this);
}
}
public void deactivate() {
Project project = getProject();
if (project != null) {
removeWidgetFromStatusBar(project, this);
}
}
@Override
public void dispose() {
deactivate();
super.dispose();
}
@NotNull
@Override
public String ID() {
return getClass().getName();
}
@Override
public WidgetPresentation getPresentation(@NotNull PlatformType type) {
return this;
}
@Override
public void selectionChanged(@NotNull FileEditorManagerEvent event) {
LOG.debug("selection changed");
update();
}
@Override
public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
LOG.debug("file opened");
update();
}
@Override
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
LOG.debug("file closed");
update();
}
@RequiredDispatchThread
@Nullable
@Override
public String getSelectedValue() {
return StringUtil.isEmpty(myText) ? "" : myPrefix + ": " + myText;
}
@NotNull
@Override
@Deprecated
public String getMaxValue() {
return "";
}
@Nullable
@Override
public String getTooltipText() {
return myTooltip;
}
@Nullable
@Override
public ListPopup getPopupStep() {
Project project = getProject();
if (project == null || project.isDisposed()) return null;
T repository = guessCurrentRepository(project);
if (repository == null) return null;
return getPopup(project, repository);
}
@Nullable
@Override
public Consumer<MouseEvent> getClickConsumer() {
// has no effect since the click opens a list popup, and the consumer is not called for the MultipleTextValuesPresentation
return null;
}
protected void updateLater() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
LOG.debug("update after repository change");
update();
}
});
}
@RequiredDispatchThread
private void update() {
myText = null;
myTooltip = null;
Project project = getProject();
if (project == null || project.isDisposed()) return;
T repository = guessCurrentRepository(project);
if (repository == null) return;
int maxLength = MAX_STRING.length() - 1; // -1, because there are arrows indicating that it is a popup
myText = StringUtil.shortenTextWithEllipsis(getFullBranchName(repository), maxLength, 5);
myTooltip = getToolTip(project);
if (myStatusBar != null) {
myStatusBar.updateWidget(ID());
}
rememberRecentRoot(repository.getRoot().getPath());
}
@Nullable
private String getToolTip(@NotNull Project project) {
T currentRepository = guessCurrentRepository(project);
if (currentRepository == null) return null;
String branchName = getFullBranchName(currentRepository);
if (isMultiRoot(project)) {
return branchName + "\n" + "Root: " + currentRepository.getRoot().getName();
}
return branchName;
}
private void installWidgetToStatusBar(@NotNull final Project project, @NotNull final StatusBarWidget widget) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
StatusBar statusBar = WindowManager.getInstance().getStatusBar(project);
if (statusBar != null && !isDisposed()) {
statusBar.addWidget(widget, "after " + (SystemInfo.isMac ? "Encoding" : "InsertOverwrite"), project);
subscribeToMappingChanged();
subscribeToRepoChangeEvents(project);
update();
}
}
});
}
private void removeWidgetFromStatusBar(@NotNull final Project project, @NotNull final StatusBarWidget widget) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
StatusBar statusBar = WindowManager.getInstance().getStatusBar(project);
if (statusBar != null && !isDisposed()) {
statusBar.removeWidget(widget.ID());
}
}
});
}
private void subscribeToMappingChanged() {
myProject.getMessageBus().connect().subscribe(VcsRepositoryManager.VCS_REPOSITORY_MAPPING_UPDATED, new VcsRepositoryMappingListener() {
@Override
public void mappingChanged() {
LOG.debug("repository mappings changed");
updateLater();
}
});
}
}