mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
git log refactoring, common way to details loading.
This commit is contained in:
@@ -12,6 +12,7 @@ import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author oleg
|
||||
@@ -75,6 +76,12 @@ public class CheckBoxList extends JBList {
|
||||
});
|
||||
}
|
||||
|
||||
public void setStringItems(final Map<String, Boolean> items) {
|
||||
for (Map.Entry<String, Boolean> entry : items.entrySet()) {
|
||||
((DefaultListModel) getModel()).addElement(new JCheckBox(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isItemSelected(int index) {
|
||||
return ((JCheckBox)getModel().getElementAt(index)).isSelected();
|
||||
}
|
||||
@@ -99,6 +106,9 @@ public class CheckBoxList extends JBList {
|
||||
this.checkBoxListListener = checkBoxListListener;
|
||||
}
|
||||
|
||||
protected void adjustRendering(final JCheckBox checkBox, final boolean selected, final boolean hasFocus) {
|
||||
}
|
||||
|
||||
private class CellRenderer implements ListCellRenderer {
|
||||
private final Border mySelectedBorder;
|
||||
private final Border myBorder;
|
||||
@@ -119,8 +129,8 @@ public class CheckBoxList extends JBList {
|
||||
checkbox.setFont(getFont(checkbox));
|
||||
checkbox.setFocusPainted(false);
|
||||
checkbox.setBorderPainted(true);
|
||||
|
||||
checkbox.setBorder(isSelected ? mySelectedBorder : myBorder);
|
||||
adjustRendering(checkbox, isSelected, cellHasFocus);
|
||||
return checkbox;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.openapi.vcs;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 6/29/11
|
||||
* Time: 11:38 PM
|
||||
*/
|
||||
public class GenericDetailsLoader<Id, Data> implements PairConsumer<Id, Data> {
|
||||
private final Consumer<Id> myLoader;
|
||||
private final ValueConsumer<Id, Data> myValueConsumer;
|
||||
private final AtomicReference<Id> myCurrentlySelected;
|
||||
|
||||
public GenericDetailsLoader(final Consumer<Id> loader, final PairConsumer<Id, Data> valueConsumer) {
|
||||
myLoader = loader;
|
||||
myValueConsumer = new ValueConsumer<Id, Data>(valueConsumer);
|
||||
myCurrentlySelected = new AtomicReference<Id>(null);
|
||||
}
|
||||
|
||||
public void updateSelection(@Nullable final Id id) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
myValueConsumer.setId(id);
|
||||
|
||||
if (! Comparing.equal(id, myCurrentlySelected.getAndSet(id))) {
|
||||
myLoader.consume(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(Id id, Data data) {
|
||||
ApplicationManager.getApplication().assertIsDispatchThread();
|
||||
myValueConsumer.consume(id, data);
|
||||
}
|
||||
|
||||
public Id getCurrentlySelected() {
|
||||
return myCurrentlySelected.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.openapi.vcs;
|
||||
|
||||
import com.intellij.util.PairConsumer;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 6/29/11
|
||||
* Time: 11:51 PM
|
||||
*/
|
||||
public class ValueConsumer<Id, Data> {
|
||||
private Id myId;
|
||||
private Id mySetId;
|
||||
private final PairConsumer<Id, Data> myConsumer;
|
||||
|
||||
protected ValueConsumer(PairConsumer<Id, Data> consumer) {
|
||||
myConsumer = consumer;
|
||||
}
|
||||
|
||||
public void consume(final Id id, final Data data) {
|
||||
if (id.equals(mySetId)) return; // already set
|
||||
if (! id.equals(myId)) return;
|
||||
mySetId = id;
|
||||
myConsumer.consume(id, data);
|
||||
}
|
||||
|
||||
public void setId(Id id) {
|
||||
myId = id;
|
||||
mySetId = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.vcsUtil;
|
||||
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 7/1/11
|
||||
* Time: 2:49 PM
|
||||
*/
|
||||
public class UIVcsUtil {
|
||||
private UIVcsUtil() {
|
||||
}
|
||||
|
||||
public static JPanel errorPanel(final String text, boolean isError) {
|
||||
final JLabel label = new JLabel(text);
|
||||
label.setForeground(isError ? SimpleTextAttributes.ERROR_ATTRIBUTES.getFgColor() : UIUtil.getInactiveTextColor());
|
||||
final JPanel wrapper = new JPanel(new GridBagLayout());
|
||||
wrapper.add(label, new GridBagConstraints(0,0,1,1,0,0,GridBagConstraints.CENTER, GridBagConstraints.NONE,
|
||||
new Insets(1,1,1,1), 0,0));
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ import com.intellij.util.containers.SLRUMap;
|
||||
import com.intellij.util.messages.MessageBusConnection;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.util.ui.tree.TreeUtil;
|
||||
import com.intellij.vcsUtil.UIVcsUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -120,9 +121,9 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
|
||||
myContentManager = contentManager;
|
||||
myVcsChangeDetailsManager = vcsChangeDetailsManager;
|
||||
myView = new ChangesListView(project);
|
||||
myNoDetailsPanel = VcsChangeDetailsManager.errorPanel("No details available", false);
|
||||
myNothingSelected = VcsChangeDetailsManager.errorPanel("Nothing selected", false);
|
||||
myNotLoadedYet = VcsChangeDetailsManager.errorPanel("Changes content is not loaded yet", false);
|
||||
myNoDetailsPanel = UIVcsUtil.errorPanel("No details available", false);
|
||||
myNothingSelected = UIVcsUtil.errorPanel("Nothing selected", false);
|
||||
myNotLoadedYet = UIVcsUtil.errorPanel("Changes content is not loaded yet", false);
|
||||
|
||||
Disposer.register(project, myView);
|
||||
myRepaintAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, project);
|
||||
@@ -263,7 +264,7 @@ public class ChangesViewManager implements ChangesViewI, JDOMExternalizable, Pro
|
||||
} else {
|
||||
final String freezed = ChangeListManager.getInstance(myProject).isFreezed();
|
||||
if (freezed != null) {
|
||||
setChangeDetailsPanel(VcsChangeDetailsManager.errorPanel(freezed, false));
|
||||
setChangeDetailsPanel(UIVcsUtil.errorPanel(freezed, false));
|
||||
return;
|
||||
}
|
||||
Pair<JPanel, Disposable> details = null;
|
||||
|
||||
+4
-14
@@ -27,12 +27,11 @@ import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.VcsKey;
|
||||
import com.intellij.openapi.vcs.changes.actions.DiffRequestFromChange;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.BeforeAfter;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.vcsUtil.UIVcsUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -104,7 +103,7 @@ public class VcsChangeDetailsManager {
|
||||
contents = myRequestFromChange.createRequestForChange(o, 0);
|
||||
}
|
||||
catch (VcsException e) {
|
||||
return new Pair<JPanel, Disposable>(errorPanel(e.getMessage(), true), null);
|
||||
return new Pair<JPanel, Disposable>(UIVcsUtil.errorPanel(e.getMessage(), true), null);
|
||||
}
|
||||
if (contents == null || contents.isEmpty()) return null;
|
||||
assert contents.size() == 1;
|
||||
@@ -155,11 +154,11 @@ public class VcsChangeDetailsManager {
|
||||
if (requestForChange == null) return null;
|
||||
if (requestForChange.isEmpty()) {
|
||||
return new Pair<JPanel, Disposable>(
|
||||
errorPanel(DiffBundle.message("diff.contents.have.differences.only.in.line.separators.message.text"), false), null);
|
||||
UIVcsUtil.errorPanel(DiffBundle.message("diff.contents.have.differences.only.in.line.separators.message.text"), false), null);
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
return new Pair<JPanel, Disposable>(errorPanel(e.getMessage(), true), null);
|
||||
return new Pair<JPanel, Disposable>(UIVcsUtil.errorPanel(e.getMessage(), true), null);
|
||||
}
|
||||
|
||||
final ChangesFragmentedDiffPanel panel =
|
||||
@@ -175,13 +174,4 @@ public class VcsChangeDetailsManager {
|
||||
o.getBeforeRevision() == null
|
||||
? "New" : o.getBeforeRevision().getRevisionNumber().asString()).append(")").toString();
|
||||
}
|
||||
|
||||
public static JPanel errorPanel(final String text, boolean isError) {
|
||||
final JLabel label = new JLabel(text);
|
||||
label.setForeground(isError ? SimpleTextAttributes.ERROR_ATTRIBUTES.getFgColor() : UIUtil.getInactiveTextColor());
|
||||
final JPanel wrapper = new JPanel(new GridBagLayout());
|
||||
wrapper.add(label, new GridBagConstraints(0,0,1,1,0,0,GridBagConstraints.CENTER, GridBagConstraints.NONE,
|
||||
new Insets(1,1,1,1), 0,0));
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,8 @@
|
||||
<projectService
|
||||
serviceInterface="git4idea.DialogManager"
|
||||
serviceImplementation="git4idea.DialogManager"/>
|
||||
<projectService serviceInterface="git4idea.history.wholeTree.GitLogSettings"
|
||||
serviceImplementation="git4idea.history.wholeTree.GitLogSettings"/>
|
||||
|
||||
<applicationService
|
||||
serviceInterface="git4idea.config.GitVcsApplicationSettings"
|
||||
|
||||
@@ -162,8 +162,12 @@ public class LowLevelAccessImpl implements LowLevelAccess {
|
||||
}
|
||||
|
||||
public List<String> getBranchesWithCommit(final SHAHash hash) throws VcsException {
|
||||
return getBranchesWithCommit(hash.getValue());
|
||||
}
|
||||
|
||||
public List<String> getBranchesWithCommit(final String hash) throws VcsException {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
GitBranch.listAsStrings(myProject, myRoot, true, true, result, hash.getValue());
|
||||
GitBranch.listAsStrings(myProject, myRoot, true, true, result, hash);
|
||||
//GitBranch.listAsStrings(myProject, myRoot, true, false, result, hash.getValue());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
package git4idea.history.browser;
|
||||
|
||||
import git4idea.GitBranch;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.TreeSet;
|
||||
@@ -66,6 +67,11 @@ public class SymbolicRefs {
|
||||
return myTags;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getCurrentName() {
|
||||
return myCurrent == null ? null : myCurrent.getName();
|
||||
}
|
||||
|
||||
public GitBranch getCurrent() {
|
||||
return myCurrent;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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 git4idea.history.wholeTree;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.ui.CheckBoxList;
|
||||
import com.intellij.ui.ListSpeedSearch;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import java.awt.*;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 6/30/11
|
||||
* Time: 8:06 PM
|
||||
*/
|
||||
public class ContainedInBranchesConfigDialog extends DialogWrapper {
|
||||
private JPanel myPanel;
|
||||
private CheckBoxList myLocalBranches;
|
||||
private CheckBoxList myRemoteBranches;
|
||||
private final Project myProject;
|
||||
private boolean myChanged;
|
||||
|
||||
public ContainedInBranchesConfigDialog(final Project project, final Collection<String> localBranches,
|
||||
Collection<String> remoteBranches, final String currentLocal, final String currentRemote) {
|
||||
super(project, true);
|
||||
myProject = project;
|
||||
setTitle("Configure branches to check reachability for");
|
||||
initUi(project, localBranches, remoteBranches, currentLocal, currentRemote);
|
||||
Disposer.register(myProject, getDisposable());
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDimensionServiceKey() {
|
||||
return "git4idea.history.wholeTree.ContainedInBranchesConfigDialog";
|
||||
}
|
||||
|
||||
private void initUi(Project project, Collection<String> localBranches, Collection<String> remoteBranches, final String currentLocal,
|
||||
final String currentRemote) {
|
||||
myPanel = new JPanel(new GridBagLayout());
|
||||
final GridBagConstraints gb =
|
||||
new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(1, 1, 1, 1), 0, 0);
|
||||
myLocalBranches = new MyCheckBoxList(currentLocal);
|
||||
myRemoteBranches = new MyCheckBoxList(currentRemote);
|
||||
|
||||
gb.gridwidth = 2;
|
||||
myPanel.add(new JLabel("Selected branches that will be used to check whether commit is reachable from (contained in)."), gb);
|
||||
|
||||
gb.insets.top = 10;
|
||||
gb.gridwidth = 1;
|
||||
++ gb.gridy;
|
||||
myPanel.add(new JLabel("Local branches"), gb);
|
||||
++ gb.gridx;
|
||||
myPanel.add(new JLabel("Remote branches"), gb);
|
||||
|
||||
gb.insets.top = 0;
|
||||
++ gb.gridy;
|
||||
gb.gridx = 0;
|
||||
gb.fill = GridBagConstraints.BOTH;
|
||||
gb.weightx = 0.5;
|
||||
gb.weighty = 1;
|
||||
myLocalBranches.setBorder(null);
|
||||
myRemoteBranches.setBorder(null);
|
||||
myPanel.add(ScrollPaneFactory.createScrollPane(myLocalBranches), gb);
|
||||
++ gb.gridx;
|
||||
myPanel.add(ScrollPaneFactory.createScrollPane(myRemoteBranches), gb);
|
||||
|
||||
final GitLogSettings gitLogSettings = GitLogSettings.getInstance(project);
|
||||
setItems(localBranches, gitLogSettings.getLocalBranchesCopy(), myLocalBranches);
|
||||
setItems(remoteBranches, gitLogSettings.getRemoteBranchesCopy(), myRemoteBranches);
|
||||
|
||||
new ListSpeedSearch(myLocalBranches);
|
||||
new ListSpeedSearch(myRemoteBranches);
|
||||
|
||||
focus(myLocalBranches);
|
||||
focus(myRemoteBranches);
|
||||
}
|
||||
|
||||
private void focus(final CheckBoxList list) {
|
||||
list.addFocusListener(new FocusAdapter() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) {
|
||||
if (list.getItemsCount() > 0 && list.getSelectedIndex() == -1) {
|
||||
list.setSelectedIndex(0);
|
||||
//list.removeSelectionInterval(0, 0);
|
||||
list.removeFocusListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isChanged() {
|
||||
return myChanged;
|
||||
}
|
||||
|
||||
private static void setItems(Collection<String> localBranches, Set<String> localBranchesCopy, final CheckBoxList list) {
|
||||
// order
|
||||
final Map<String, Boolean> localBranchesState = new TreeMap<String, Boolean>();
|
||||
for (String localBranch : localBranches) {
|
||||
localBranchesState.put(localBranch, localBranchesCopy.contains(localBranch));
|
||||
}
|
||||
list.setStringItems(localBranchesState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return myLocalBranches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(300, 400);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
final GitLogSettings gitLogSettings = GitLogSettings.getInstance(myProject);
|
||||
final ArrayList<String> local = gatherSelected((DefaultListModel)myLocalBranches.getModel());
|
||||
final ArrayList<String> remote = gatherSelected((DefaultListModel)myRemoteBranches.getModel());
|
||||
if (gitLogSettings.setIfChanged(local, remote)) {
|
||||
myChanged = true;
|
||||
}
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
private ArrayList<String> gatherSelected(DefaultListModel localModel) {
|
||||
final ArrayList<String> selected = new ArrayList<String>();
|
||||
final Enumeration<?> elements = localModel.elements();
|
||||
while (elements.hasMoreElements()) {
|
||||
final JCheckBox cb = (JCheckBox)elements.nextElement();
|
||||
if (cb.isSelected()) {
|
||||
selected.add(cb.getText());
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
private static class MyCheckBoxList extends CheckBoxList {
|
||||
private final String myBold;
|
||||
private final static Border FOCUSED_BORDER = UIManager.getBorder("List.focusCellHighlightBorder");
|
||||
private final EmptyBorder myEmptyBorder;
|
||||
|
||||
private MyCheckBoxList(String bold) {
|
||||
myBold = bold;
|
||||
final Insets borderInsets = FOCUSED_BORDER.getBorderInsets(new JCheckBox());
|
||||
myEmptyBorder = new EmptyBorder(borderInsets);
|
||||
setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adjustRendering(JCheckBox checkBox, final boolean selected, final boolean hasFocus) {
|
||||
checkBox.setFocusPainted(false);
|
||||
if (myBold != null && myBold.equals(checkBox.getText())) {
|
||||
checkBox.setFont(checkBox.getFont().deriveFont(Font.BOLD));
|
||||
} else {
|
||||
checkBox.setFont(checkBox.getFont().deriveFont(Font.PLAIN));
|
||||
}
|
||||
if (hasFocus) {
|
||||
checkBox.setBorder(FOCUSED_BORDER);
|
||||
} else {
|
||||
checkBox.setBorder(myEmptyBorder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,14 +21,13 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.vcs.VcsException;
|
||||
import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
|
||||
import com.intellij.openapi.vcs.changes.committed.AbstractCalledLater;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.containers.SLRUMap;
|
||||
import git4idea.history.browser.GitCommit;
|
||||
import git4idea.history.browser.LowLevelAccessImpl;
|
||||
import git4idea.history.browser.SHAHash;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -49,7 +48,7 @@ public class DetailsCache {
|
||||
private final DetailsLoaderImpl myDetailsLoader;
|
||||
private final ModalityState myModalityState;
|
||||
private final BackgroundTaskQueue myQueue;
|
||||
private AbstractCalledLater myRefresh;
|
||||
private UIRefresh myRefresh;
|
||||
private final Map<VirtualFile, Map<AbstractHash, String>> myStash;
|
||||
private final Object myLock;
|
||||
private final static Logger LOG = Logger.getInstance("git4idea.history.wholeTree.DetailsCache");
|
||||
@@ -64,12 +63,7 @@ public class DetailsCache {
|
||||
myModalityState = modalityState;
|
||||
myQueue = queue;
|
||||
myStash = new HashMap<VirtualFile, Map<AbstractHash,String>>();
|
||||
myRefresh = new AbstractCalledLater(project, myModalityState) {
|
||||
@Override
|
||||
public void run() {
|
||||
uiRefresh.detailsLoaded();
|
||||
}
|
||||
};
|
||||
myRefresh = uiRefresh;
|
||||
myLock = new Object();
|
||||
myCache = new SLRUMap<Pair<VirtualFile, AbstractHash>, GitCommit>(ourSize, 50);
|
||||
myBranches = new SLRUMap<Pair<VirtualFile, AbstractHash>, List<String>>(10, 10);
|
||||
@@ -92,7 +86,12 @@ public class DetailsCache {
|
||||
myCache.put(new Pair<VirtualFile, AbstractHash>(root, commit.getShortHash()), commit);
|
||||
}
|
||||
}
|
||||
myRefresh.callMe();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myRefresh.detailsLoaded();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void rootsChanged(final Collection<VirtualFile> roots) {
|
||||
@@ -133,17 +132,23 @@ public class DetailsCache {
|
||||
}
|
||||
}
|
||||
|
||||
public void clearBranches() {
|
||||
synchronized (myLock) {
|
||||
myBranches.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadAndPutBranches(final VirtualFile root,
|
||||
final SHAHash hash,
|
||||
final AbstractHash abstractHash,
|
||||
final Consumer<List<String>> continuation) {
|
||||
final Consumer<List<String>> continuation, final Processor<AbstractHash> recheck) {
|
||||
myQueue.run(new Task.Backgroundable(myProject, "Load contained in branches", true, BackgroundFromStartOption.getInstance()) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
if (! recheck.process(abstractHash)) return;
|
||||
if (getBranches(root, abstractHash) != null) return;
|
||||
final List<String> branches;
|
||||
try {
|
||||
branches = new LowLevelAccessImpl(myProject, root).getBranchesWithCommit(hash);
|
||||
branches = new LowLevelAccessImpl(myProject, root).getBranchesWithCommit(abstractHash.getString());
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.info(e);
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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 git4idea.history.wholeTree;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.BrowserHyperlinkListener;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import com.intellij.vcsUtil.UIVcsUtil;
|
||||
import git4idea.history.browser.CaptionIcon;
|
||||
import git4idea.history.browser.GitCommit;
|
||||
import git4idea.history.browser.SymbolicRefs;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 7/1/11
|
||||
* Time: 2:27 PM
|
||||
*/
|
||||
public class GitLogDetailsPanel {
|
||||
public static final String CONFIGURE_BRANCHES = "configure_branches";
|
||||
private final static String NOTHING_SELECTED = "nothingSelected";
|
||||
private final static String LOADING = "loading";
|
||||
private final static String DATA = "data";
|
||||
private static final String MULTIPLE_SELECTED = "multiple_selected";
|
||||
|
||||
private final JPanel myPanel;
|
||||
private JPanel myMarksPanel;
|
||||
|
||||
private final MyPresentationData myPresentationData;
|
||||
|
||||
private final HtmlHighlighter myHtmlHighlighter;
|
||||
private JEditorPane myJEditorPane;
|
||||
private VirtualFile myRoot;
|
||||
|
||||
public GitLogDetailsPanel(final Project myProject, final DetailsCache detailsCache, final Convertor<VirtualFile, SymbolicRefs> refsProvider) {
|
||||
myPanel = new JPanel(new CardLayout());
|
||||
myPanel.add(UIVcsUtil.errorPanel("Nothing selected", false), NOTHING_SELECTED);
|
||||
myPanel.add(UIVcsUtil.errorPanel("Loading...", false), LOADING);
|
||||
myPanel.add(UIVcsUtil.errorPanel("Several commits selected", false), MULTIPLE_SELECTED);
|
||||
|
||||
myHtmlHighlighter = new HtmlHighlighter();
|
||||
myPresentationData = new MyPresentationData(myProject, detailsCache, myHtmlHighlighter);
|
||||
|
||||
final JPanel wrapper = new JPanel(new GridBagLayout());
|
||||
final GridBagConstraints gb = new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL,
|
||||
new Insets(1, 1, 1, 1), 0, 0);
|
||||
|
||||
myJEditorPane = new JEditorPane(UIUtil.HTML_MIME, "");
|
||||
myJEditorPane.setPreferredSize(new Dimension(150, 100));
|
||||
myJEditorPane.setEditable(false);
|
||||
myJEditorPane.setBackground(UIUtil.getComboBoxDisabledBackground());
|
||||
myJEditorPane.addHyperlinkListener(new BrowserHyperlinkListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent e) {
|
||||
/*if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED && CONFIGURE_BRANCHES.equals(e.getDescription())) {
|
||||
if (myRoot == null) return;
|
||||
final SymbolicRefs symbolicRefs = refsProvider.convert(myRoot);
|
||||
if (symbolicRefs == null) return;
|
||||
final TreeSet<String> localBranches = symbolicRefs.getLocalBranches();
|
||||
if (localBranches == null || localBranches.isEmpty()) {
|
||||
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Branches is not loaded yet", MessageType.WARNING);
|
||||
}
|
||||
final ContainedInBranchesConfigDialog dialog =
|
||||
new ContainedInBranchesConfigDialog(myProject, localBranches, symbolicRefs.getRemoteBranches(),
|
||||
symbolicRefs.getCurrentName(), symbolicRefs.getTrackedRemoteName());
|
||||
dialog.show();
|
||||
if (dialog.isChanged()) {
|
||||
detailsCache.clearBranches();
|
||||
}
|
||||
return;
|
||||
}*/
|
||||
super.hyperlinkUpdate(e);
|
||||
}
|
||||
});
|
||||
|
||||
myMarksPanel = new JPanel();
|
||||
final BoxLayout boxLayout = new BoxLayout(myMarksPanel, BoxLayout.X_AXIS);
|
||||
myMarksPanel.setLayout(boxLayout);
|
||||
gb.weightx = 1;
|
||||
wrapper.add(myMarksPanel, gb);
|
||||
++ gb.gridy;
|
||||
gb.weighty = 1;
|
||||
gb.fill = GridBagConstraints.BOTH;
|
||||
final JBScrollPane tableScroll = new JBScrollPane(myJEditorPane);
|
||||
tableScroll.setBorder(null);
|
||||
myJEditorPane.setBorder(null);
|
||||
wrapper.add(tableScroll, gb);
|
||||
myJEditorPane.setBackground(UIUtil.getTableBackground());
|
||||
myMarksPanel.setBackground(UIUtil.getTableBackground());
|
||||
wrapper.setBackground(UIUtil.getTableBackground());
|
||||
|
||||
myPanel.add(wrapper, DATA);
|
||||
((CardLayout) myPanel.getLayout()).show(myPanel, NOTHING_SELECTED);
|
||||
}
|
||||
|
||||
public HtmlHighlighter getHtmlHighlighter() {
|
||||
return myHtmlHighlighter;
|
||||
}
|
||||
|
||||
public void severalSelected() {
|
||||
myPresentationData.clear();
|
||||
((CardLayout) myPanel.getLayout()).show(myPanel, MULTIPLE_SELECTED);
|
||||
}
|
||||
|
||||
public void nothingSelected() {
|
||||
myPresentationData.clear();
|
||||
((CardLayout) myPanel.getLayout()).show(myPanel, NOTHING_SELECTED);
|
||||
}
|
||||
|
||||
public void setBranches(final java.util.List<String> branchesList) {
|
||||
myPresentationData.setBranches(branchesList);
|
||||
changeDetailsText();
|
||||
}
|
||||
|
||||
public void loading(VirtualFile root) {
|
||||
myRoot = root;
|
||||
myPresentationData.clear();
|
||||
((CardLayout) myPanel.getLayout()).show(myPanel, LOADING);
|
||||
}
|
||||
|
||||
public void setData(VirtualFile root, @NotNull final GitCommit commit) {
|
||||
myRoot = root;
|
||||
redrawBranchLabels(commit);
|
||||
|
||||
myPresentationData.setCommit(root, commit);
|
||||
((CardLayout) myPanel.getLayout()).show(myPanel, DATA);
|
||||
|
||||
changeDetailsText();
|
||||
}
|
||||
|
||||
private void changeDetailsText() {
|
||||
if (myPresentationData.isReady()) {
|
||||
myJEditorPane.setText(myPresentationData.getText());
|
||||
myPanel.revalidate();
|
||||
myPanel.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private void redrawBranchLabels(GitCommit commit) {
|
||||
final Font tableFont = myJEditorPane.getFont();
|
||||
final Font font = tableFont.deriveFont((float)(tableFont.getSize() - 1));
|
||||
final String currentBranch = commit.getCurrentBranch();
|
||||
myMarksPanel.removeAll();
|
||||
for (String s : commit.getLocalBranches()) {
|
||||
myMarksPanel.add(new JLabel(new CaptionIcon(GitLogUI.Colors.local, font, s, myMarksPanel, CaptionIcon.Form.SQUARE, false,
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
for (String s : commit.getRemoteBranches()) {
|
||||
myMarksPanel.add(new JLabel(new CaptionIcon(GitLogUI.Colors.remote, font, s, myMarksPanel, CaptionIcon.Form.SQUARE, false,
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
for (String s : commit.getTags()) {
|
||||
myMarksPanel.add(new JLabel(new CaptionIcon(GitLogUI.Colors.tag, font, s, myMarksPanel, CaptionIcon.Form.ROUNDED, false,
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
}
|
||||
|
||||
public JPanel getComponent() {
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
private static class HtmlHighlighter extends HighlightingRendererBase {
|
||||
private final StringBuilder mySb;
|
||||
|
||||
private HtmlHighlighter() {
|
||||
super();
|
||||
mySb = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void highlight(String s) {
|
||||
mySb.append("<font color=rgb(255,128,0)>").append(s).append("</font>");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void usual(String s) {
|
||||
mySb.append(s);
|
||||
}
|
||||
|
||||
public String getResult(final String text) {
|
||||
mySb.setLength(0);
|
||||
tryHighlight(text);
|
||||
return mySb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyPresentationData {
|
||||
private String myStartPattern;
|
||||
private final String myEndPattern = "</td></tr></table></body></html>";
|
||||
private String myBranches;
|
||||
private final Project myProject;
|
||||
private final DetailsCache myDetailsCache;
|
||||
private final HtmlHighlighter myHighlighter;
|
||||
|
||||
private MyPresentationData(final Project project, final DetailsCache detailsCache, final HtmlHighlighter highlighter) {
|
||||
myProject = project;
|
||||
myDetailsCache = detailsCache;
|
||||
myHighlighter = highlighter;
|
||||
}
|
||||
|
||||
public void setCommit(final VirtualFile root, final GitCommit c) {
|
||||
final String hash = myHighlighter.getResult(c.getHash().getValue());
|
||||
final String author = myHighlighter.getResult(c.getAuthor());
|
||||
final String committer = myHighlighter.getResult(c.getCommitter());
|
||||
final String comment = IssueLinkHtmlRenderer.formatTextWithLinks(myProject, c.getDescription(),
|
||||
new Convertor<String, String>() {
|
||||
@Override
|
||||
public String convert(String o) {
|
||||
return myHighlighter.getResult(o);
|
||||
}
|
||||
});
|
||||
|
||||
final StringBuilder sb = new StringBuilder().append("<html><head>").append(UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()))
|
||||
.append("</head><body><table>");
|
||||
final String stashName = myDetailsCache.getStashName(root, c.getShortHash());
|
||||
if (! StringUtil.isEmptyOrSpaces(stashName)) {
|
||||
sb.append("<tr valign=\"top\"><td><b>").append(stashName).append("</b></td><td></td></tr>");
|
||||
}
|
||||
sb.append("<tr valign=\"top\"><td><i>Hash:</i></td><td>").append(
|
||||
hash).append("</td></tr>" + "<tr valign=\"top\"><td><i>Author:</i></td><td>")
|
||||
.append(author).append(" (").append(c.getAuthorEmail()).append(") <i>at</i> ")
|
||||
.append(DateFormatUtil.formatPrettyDateTime(c.getAuthorTime()))
|
||||
.append("</td></tr>" + "<tr valign=\"top\"><td><i>Commiter:</i></td><td>")
|
||||
.append(committer).append(" (").append(c.getComitterEmail()).append(") <i>at</i> ")
|
||||
.append(DateFormatUtil.formatPrettyDateTime(c.getDate())).append(
|
||||
"</td></tr>" + "<tr valign=\"top\"><td><i>Description:</i></td><td><b>")
|
||||
.append(comment).append("</b></td></tr>");
|
||||
sb.append("<tr valign=\"top\"><td><i>Contained in branches:</i></td><td>");
|
||||
myStartPattern = sb.toString();
|
||||
}
|
||||
|
||||
public void setBranches(final java.util.List<String> branches) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (branches != null && (! branches.isEmpty())) {
|
||||
for (int i = 0; i < branches.size(); i++) {
|
||||
String s = branches.get(i);
|
||||
sb.append(s);
|
||||
if (i + 1 < branches.size()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
myBranches = sb.toString();
|
||||
} else if (branches != null && branches.isEmpty()) {
|
||||
myBranches = "<font color=gray><no branches></font><br/>";
|
||||
} else {
|
||||
myBranches = "<font color=gray>Loading...</font><br/>";
|
||||
}
|
||||
}
|
||||
|
||||
protected String getBranches() {
|
||||
return myBranches == null ? "<font color=gray>Loading...</font>" : myBranches;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return myStartPattern != null;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return myStartPattern + getBranches() + myEndPattern;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
myBranches = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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 git4idea.history.wholeTree;
|
||||
|
||||
import com.intellij.openapi.components.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 7/1/11
|
||||
* Time: 1:11 PM
|
||||
*/
|
||||
@State(
|
||||
name = "GitLogSettings",
|
||||
storages = {
|
||||
@Storage(
|
||||
id ="other",
|
||||
file = "$PROJECT_FILE$"
|
||||
)
|
||||
,@Storage(id = "dir", file = "$PROJECT_CONFIG_DIR$/vcs.xml", scheme = StorageScheme.DIRECTORY_BASED)
|
||||
}
|
||||
)
|
||||
public class GitLogSettings implements PersistentStateComponent<GitLogSettings.MyState> {
|
||||
private MyState myState = new MyState();
|
||||
|
||||
public boolean setIfChanged(ArrayList<String> local, ArrayList<String> remote) {
|
||||
if (Comparing.haveEqualElements(myState.myContainedLocalBranches, local) && Comparing.haveEqualElements(myState.myContainedRemoteBranches, remote)) {
|
||||
return false;
|
||||
}
|
||||
setLocal(local);
|
||||
setRemote(remote);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class MyState {
|
||||
public List<String> myContainedLocalBranches = new ArrayList<String>();
|
||||
public List<String> myContainedRemoteBranches = new ArrayList<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MyState getState() {
|
||||
return myState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(MyState state) {
|
||||
myState = state;
|
||||
}
|
||||
|
||||
public static GitLogSettings getInstance(final Project project) {
|
||||
return ServiceManager.getService(project, GitLogSettings.class);
|
||||
}
|
||||
|
||||
public Set<String> getLocalBranchesCopy() {
|
||||
return myState.myContainedLocalBranches == null ? Collections.<String>emptySet() : new HashSet<String>(myState.myContainedLocalBranches);
|
||||
}
|
||||
|
||||
public Set<String> getRemoteBranchesCopy() {
|
||||
return myState.myContainedRemoteBranches == null ? Collections.<String>emptySet() : new HashSet<String>(myState.myContainedRemoteBranches);
|
||||
}
|
||||
|
||||
public void iterateBranches(final PairConsumer<String, Boolean> consumer) {
|
||||
for (String item : myState.myContainedLocalBranches) {
|
||||
consumer.consume(item, true);
|
||||
}
|
||||
for (String item : myState.myContainedRemoteBranches) {
|
||||
consumer.consume(item, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLocal(final List<String> local) {
|
||||
Collections.sort(local);
|
||||
myState.myContainedLocalBranches = local;
|
||||
}
|
||||
|
||||
public void setRemote(final List<String> branches) {
|
||||
Collections.sort(branches);
|
||||
myState.myContainedRemoteBranches = branches;
|
||||
}
|
||||
}
|
||||
@@ -28,22 +28,23 @@ import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.AbstractFilterChildren;
|
||||
import com.intellij.openapi.vcs.CheckSamePattern;
|
||||
import com.intellij.openapi.vcs.ComparableComparator;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.*;
|
||||
import com.intellij.openapi.vcs.changes.Change;
|
||||
import com.intellij.openapi.vcs.changes.committed.CommittedChangesTreeBrowser;
|
||||
import com.intellij.openapi.vcs.changes.committed.RepositoryChangesBrowser;
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkHtmlRenderer;
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer;
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.TableLinkMouseListener;
|
||||
import com.intellij.openapi.vcs.ui.SearchFieldAction;
|
||||
import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.ColoredTableCellRenderer;
|
||||
import com.intellij.ui.PopupHandler;
|
||||
import com.intellij.ui.ScrollPaneFactory;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.PairConsumer;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.Convertor;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
@@ -86,19 +87,19 @@ public class GitLogUI implements Disposable {
|
||||
private JBTable myJBTable;
|
||||
private RepositoryChangesBrowser myRepositoryChangesBrowser;
|
||||
private boolean myDataBeingAdded;
|
||||
private boolean myMissingSelectionData;
|
||||
private CardLayout myRepoLayout;
|
||||
private JPanel myRepoPanel;
|
||||
private boolean myStarted;
|
||||
// private JTextField myFilterField;
|
||||
private String myPreviousFilter;
|
||||
private List<String> mySearchContext;
|
||||
private final CommentSearchContext myCommentSearchContext;
|
||||
private List<String> myUsersSearchContext;
|
||||
private String mySelectedBranch;
|
||||
private BranchSelectorAction myBranchSelectorAction;
|
||||
private MySpecificDetails myDetails;
|
||||
private final DescriptionRenderer myDescriptionRenderer;
|
||||
private final Speedometer mySelectionSpeedometer;
|
||||
|
||||
private GenericDetailsLoader<CommitI, GitCommit> myDetailsLoader;
|
||||
private GenericDetailsLoader<CommitI, List<String>> myBranchesLoader;
|
||||
private GitLogDetailsPanel myDetailsPanel;
|
||||
|
||||
private StepType myState;
|
||||
private MoreAction myMoreAction;
|
||||
@@ -107,24 +108,47 @@ public class GitLogUI implements Disposable {
|
||||
private MyCherryPick myCherryPickAction;
|
||||
private MyRefreshAction myRefreshAction;
|
||||
private AnAction myCopyHashAction;
|
||||
// todo group somewhere??
|
||||
private Consumer<CommitI> myDetailsLoaderImpl;
|
||||
private Consumer<CommitI> myBranchesLoaderImpl;
|
||||
private final RequestsMerger mySelectionRequestsMerger;
|
||||
|
||||
private final TableCellRenderer myAuthorRenderer;
|
||||
|
||||
public GitLogUI(Project project, final Mediator mediator) {
|
||||
myProject = project;
|
||||
myMediator = mediator;
|
||||
mySearchContext = new ArrayList<String>();
|
||||
myCommentSearchContext = new CommentSearchContext();
|
||||
myUsersSearchContext = new ArrayList<String>();
|
||||
myRefs = new HashMap<VirtualFile, SymbolicRefs>();
|
||||
myRecalculatedCommon = new SymbolicRefs();
|
||||
myPreviousFilter = "";
|
||||
myDetails = new MySpecificDetails(myProject);
|
||||
myDescriptionRenderer = new DescriptionRenderer();
|
||||
mySelectionSpeedometer = new Speedometer(20, 400);
|
||||
myCommentSearchContext.addHighlighter(myDescriptionRenderer.myInner.myWorker);
|
||||
|
||||
mySelectionRequestsMerger = new RequestsMerger(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
selectionChanged();
|
||||
}
|
||||
}, new Consumer<Runnable>() {
|
||||
@Override
|
||||
public void consume(Runnable runnable) {
|
||||
SwingUtilities.invokeLater(runnable);
|
||||
}
|
||||
});
|
||||
createTableModel();
|
||||
myState = StepType.CONTINUE;
|
||||
|
||||
initUiRefresh();
|
||||
myAuthorRenderer = new HighLightingRenderer(HIGHLIGHT_TEXT_ATTRIBUTES, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
}
|
||||
|
||||
private void initUiRefresh() {
|
||||
myUIRefresh = new UIRefresh() {
|
||||
@Override
|
||||
public void detailsLoaded() {
|
||||
tryRefreshDetails();
|
||||
fireTableRepaint();
|
||||
}
|
||||
|
||||
@@ -273,31 +297,70 @@ public class GitLogUI implements Disposable {
|
||||
}
|
||||
});
|
||||
|
||||
/*final JComponent specificDetails = myDetails.create();
|
||||
final Content specificDetailsContent = myUi.createContent("Specific0", specificDetails, "Details", PlatformIcons.UNSELECT_ALL_ICON, null);
|
||||
myUi.addContent(specificDetailsContent, 0, PlaceInGrid.bottom, false);
|
||||
repoContent.setCloseable(false);
|
||||
repoContent.setPinned(true);
|
||||
createDetailLoaders();
|
||||
}
|
||||
|
||||
myUi.getDefaults().initTabDefaults(0, "Git log", null);*/
|
||||
|
||||
// todo should look like it, but the behaviour of search differs
|
||||
/*new TableSpeedSearch(myJBTable, new Convertor<Object, String>() {
|
||||
private void createDetailLoaders() {
|
||||
myDetailsLoaderImpl = new Consumer<CommitI>() {
|
||||
@Override
|
||||
public String convert(Object o) {
|
||||
if (o instanceof CommitI) {
|
||||
return ((CommitI) o).getDecorationString();
|
||||
public void consume(final CommitI commitI) {
|
||||
if (commitI == null) return;
|
||||
final GitCommit gitCommit = fullCommitPresentation(commitI);
|
||||
|
||||
if (gitCommit == null) {
|
||||
final MultiMap<VirtualFile, AbstractHash> question = new MultiMap<VirtualFile, AbstractHash>();
|
||||
question.putValue(commitI.selectRepository(myRootsUnderVcs), commitI.getHash());
|
||||
myDetailsCache.acceptQuestion(question);
|
||||
} else {
|
||||
myDetailsLoader.consume(commitI, gitCommit);
|
||||
}
|
||||
return o == null ? null : o.toString();
|
||||
}
|
||||
});*/
|
||||
};
|
||||
myDetailsLoader = new GenericDetailsLoader<CommitI, GitCommit>(myDetailsLoaderImpl, new PairConsumer<CommitI, GitCommit>() {
|
||||
@Override
|
||||
public void consume(CommitI commitI, GitCommit commit) {
|
||||
myDetailsPanel.setData(commitI.selectRepository(myRootsUnderVcs), commit);
|
||||
}
|
||||
});
|
||||
|
||||
//myUi.getDefaults().initTabDefaults(0, "Git log", );
|
||||
/* myUi = RunnerLayoutUi.Factory.getInstance(project).create("Debug", "unknown!", sessionName, this);
|
||||
myUi.getDefaults().initTabDefaults(0, "Debug", null);
|
||||
myBranchesLoaderImpl = new Consumer<CommitI>() {
|
||||
private Processor<AbstractHash> myRecheck;
|
||||
|
||||
myUi.getOptions().setTopToolbar(createTopToolbar(), ActionPlaces.DEBUGGER_TOOLBAR);
|
||||
*/
|
||||
{
|
||||
myRecheck = new Processor<AbstractHash>() {
|
||||
@Override
|
||||
public boolean process(AbstractHash abstractHash) {
|
||||
if (myBranchesLoader.getCurrentlySelected() == null) return false;
|
||||
return Comparing.equal(myBranchesLoader.getCurrentlySelected().getHash(), abstractHash);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(final CommitI commitI) {
|
||||
if (commitI == null) return;
|
||||
final VirtualFile root = commitI.selectRepository(myRootsUnderVcs);
|
||||
final List<String> branches = myDetailsCache.getBranches(root, commitI.getHash());
|
||||
if (branches != null) {
|
||||
myBranchesLoader.consume(commitI, branches);
|
||||
return;
|
||||
}
|
||||
|
||||
myDetailsCache.loadAndPutBranches(root, commitI.getHash(), new Consumer<List<String>>() {
|
||||
@Override
|
||||
public void consume(List<String> strings) {
|
||||
if (myProject.isDisposed() || strings == null) return;
|
||||
myBranchesLoader.consume(commitI, strings);
|
||||
}
|
||||
}, myRecheck);
|
||||
}
|
||||
};
|
||||
myBranchesLoader = new GenericDetailsLoader<CommitI, List<String>>(myBranchesLoaderImpl, new PairConsumer<CommitI, List<String>>() {
|
||||
@Override
|
||||
public void consume(CommitI commitI, List<String> strings) {
|
||||
myDetailsPanel.setBranches(strings);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private JComponent createRepositoryBrowserDetails() {
|
||||
@@ -308,9 +371,7 @@ public class GitLogUI implements Disposable {
|
||||
myJBTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
if (! myDataBeingAdded && (! e.getValueIsAdjusting())) {
|
||||
selectionChanged();
|
||||
}
|
||||
mySelectionRequestsMerger.request();
|
||||
}
|
||||
});
|
||||
myRepoPanel.add("main", myRepositoryChangesBrowser);
|
||||
@@ -323,24 +384,87 @@ public class GitLogUI implements Disposable {
|
||||
}
|
||||
|
||||
private void selectionChanged() {
|
||||
mySelectionSpeedometer.event();
|
||||
|
||||
if (myDataBeingAdded) {
|
||||
mySelectionRequestsMerger.request();
|
||||
return;
|
||||
}
|
||||
final int[] rows = myJBTable.getSelectedRows();
|
||||
myDetails.refresh(null, null);
|
||||
selectionChangedForDetails(rows);
|
||||
|
||||
if (rows.length == 0) {
|
||||
myRepoLayout.show(myRepoPanel, "empty");
|
||||
myRepoPanel.repaint();
|
||||
myMissingSelectionData = false;
|
||||
return;
|
||||
} else if (rows.length >= 10) {
|
||||
myRepoLayout.show(myRepoPanel, "tooMuch");
|
||||
myRepoPanel.repaint();
|
||||
myMissingSelectionData = false;
|
||||
return;
|
||||
}
|
||||
myRepoLayout.show(myRepoPanel, "loading");
|
||||
myRepoPanel.repaint();
|
||||
updateDetailsFromSelection();
|
||||
|
||||
gatherNotLoadedData();
|
||||
}
|
||||
|
||||
private static class MeaningfulSelection {
|
||||
private CommitI myCommitI;
|
||||
private int myMeaningfulRows;
|
||||
|
||||
private MeaningfulSelection(int[] rows, final BigTableTableModel tableModel) {
|
||||
myMeaningfulRows = 0;
|
||||
for (int row : rows) {
|
||||
myCommitI = tableModel.getCommitAt(row);
|
||||
if (!myCommitI.holdsDecoration()) {
|
||||
++myMeaningfulRows;
|
||||
if (myMeaningfulRows > 1) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CommitI getCommit() {
|
||||
return myCommitI;
|
||||
}
|
||||
|
||||
public int getMeaningfulRows() {
|
||||
return myMeaningfulRows;
|
||||
}
|
||||
}
|
||||
|
||||
private void tryRefreshDetails() {
|
||||
MeaningfulSelection meaningfulSelection = new MeaningfulSelection(myJBTable.getSelectedRows(), myTableModel);
|
||||
if (meaningfulSelection.getMeaningfulRows() == 1) {
|
||||
// still have one item selected which probably was not loaded
|
||||
final CommitI commit = meaningfulSelection.getCommit();
|
||||
myDetailsLoaderImpl.consume(commit);
|
||||
myBranchesLoaderImpl.consume(commit);
|
||||
}
|
||||
}
|
||||
|
||||
private void selectionChangedForDetails(int[] rows) {
|
||||
MeaningfulSelection meaningfulSelection = new MeaningfulSelection(rows, myTableModel);
|
||||
int meaningfulRows = meaningfulSelection.getMeaningfulRows();
|
||||
CommitI commitAt = meaningfulSelection.getCommit();
|
||||
|
||||
if (meaningfulRows == 0) {
|
||||
myDetailsPanel.nothingSelected();
|
||||
myDetailsLoader.updateSelection(null);
|
||||
myBranchesLoader.updateSelection(null);
|
||||
} else if (meaningfulRows == 1) {
|
||||
final GitCommit commit = fullCommitPresentation(commitAt);
|
||||
if (commit == null) {
|
||||
myDetailsPanel.loading(commitAt.selectRepository(myRootsUnderVcs));
|
||||
}
|
||||
myDetailsLoader.updateSelection(commitAt);
|
||||
myBranchesLoader.updateSelection(commitAt);
|
||||
} else {
|
||||
myDetailsPanel.severalSelected();
|
||||
myDetailsLoader.updateSelection(null);
|
||||
myBranchesLoader.updateSelection(null);
|
||||
}
|
||||
}
|
||||
|
||||
private GitCommit fullCommitPresentation(CommitI commitAt) {
|
||||
return myDetailsCache.convert(commitAt.selectRepository(myRootsUnderVcs), commitAt.getHash());
|
||||
}
|
||||
|
||||
private static JPanel panelWithCenteredText(final String text) {
|
||||
@@ -353,71 +477,27 @@ public class GitLogUI implements Disposable {
|
||||
return jPanel;
|
||||
}
|
||||
|
||||
public void updateSelection() {
|
||||
updateBranchesFor();
|
||||
if (! myMissingSelectionData) return;
|
||||
updateDetailsFromSelection();
|
||||
public void updateByScroll() {
|
||||
gatherNotLoadedData();
|
||||
}
|
||||
|
||||
private void updateBranchesFor() {
|
||||
final int[] rows = myJBTable.getSelectedRows();
|
||||
if (rows.length == 1 && myDetails.isMissingBranchesInfo() && mySelectionSpeedometer.getSpeed() < 0.1) {
|
||||
final CommitI commit = myTableModel.getCommitAt(rows[0]);
|
||||
final VirtualFile root = commit.selectRepository(myRootsUnderVcs);
|
||||
if (commit.holdsDecoration()) return;
|
||||
final GitCommit gitCommit = myDetailsCache.convert(root, commit.getHash());
|
||||
if (gitCommit == null) return;
|
||||
final List<String> branches = myDetailsCache.getBranches(root, commit.getHash());
|
||||
if (branches != null) {
|
||||
myDetails.putBranches(root, gitCommit, branches);
|
||||
}
|
||||
|
||||
final CommitI commitI = myTableModel.getCommitAt(rows[0]);
|
||||
if (! commit.equals(commitI)) return;
|
||||
myDetailsCache.loadAndPutBranches(root, gitCommit.getHash(), commit.getHash(), new Consumer<List<String>>() {
|
||||
@Override
|
||||
public void consume(List<String> strings) {
|
||||
if (myProject.isDisposed()) return;
|
||||
|
||||
final int[] afterRows = myJBTable.getSelectedRows();
|
||||
if (myDetails.isMissingBranchesInfo() && afterRows.length == 1 && afterRows[0] == rows[0]) {
|
||||
final CommitI afterCommit = myTableModel.getCommitAt(rows[0]);
|
||||
if (afterCommit.holdsDecoration() || (! afterCommit.equals(commit))) return;
|
||||
myDetails.putBranches(root, gitCommit, strings);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDetailsFromSelection() {
|
||||
private void gatherNotLoadedData() {
|
||||
if (myDataBeingAdded) return;
|
||||
myMissingSelectionData = false;
|
||||
final int[] rows = myJBTable.getSelectedRows();
|
||||
if (rows.length == 1) {
|
||||
final CommitI commitI = myTableModel.getCommitAt(rows[0]);
|
||||
if (commitI != null && (! commitI.holdsDecoration())) {
|
||||
final VirtualFile root = commitI.selectRepository(myRootsUnderVcs);
|
||||
final GitCommit convert = myDetailsCache.convert(root, commitI.getHash());
|
||||
if (convert != null) {
|
||||
myDetails.refresh(root, convert);
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<GitCommit> commits = new ArrayList<GitCommit>();
|
||||
final MultiMap<VirtualFile,AbstractHash> missingHashes = new MultiMap<VirtualFile, AbstractHash>();
|
||||
for (int i = rows.length - 1; i >= 0; --i) {
|
||||
final int row = rows[i];
|
||||
final CommitI commitI = myTableModel.getCommitAt(row);
|
||||
if (commitI == null || commitI.holdsDecoration()) continue;
|
||||
VirtualFile root = commitI.selectRepository(myRootsUnderVcs);
|
||||
AbstractHash hash = commitI.getHash();
|
||||
final GitCommit details = myDetailsCache.convert(root, hash);
|
||||
commits.add(details);
|
||||
myMissingSelectionData |= details == null;
|
||||
missingHashes.putValue(root, hash);
|
||||
final GitCommit details = fullCommitPresentation(commitI);
|
||||
if (details == null) {
|
||||
missingHashes.putValue(commitI.selectRepository(myRootsUnderVcs), commitI.getHash());
|
||||
} else if (missingHashes.isEmpty()) { // no sense in collecting commits when s
|
||||
commits.add(details);
|
||||
}
|
||||
}
|
||||
if (myMissingSelectionData) {
|
||||
if (! missingHashes.isEmpty()) {
|
||||
myDetailsCache.acceptQuestion(missingHashes);
|
||||
return;
|
||||
}
|
||||
@@ -481,7 +561,7 @@ public class GitLogUI implements Disposable {
|
||||
myMyChangeListener = new GitTableScrollChangeListener(myJBTable, myDetailsCache, myTableModel, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateSelection();
|
||||
updateByScroll();
|
||||
}
|
||||
});
|
||||
scrollPane.getViewport().addChangeListener(myMyChangeListener);
|
||||
@@ -492,10 +572,15 @@ public class GitLogUI implements Disposable {
|
||||
mainBorderWrapper.add(scrollPane, BorderLayout.CENTER);
|
||||
mainBorderWrapper.setBorder(BorderFactory.createLineBorder(UIUtil.getBorderColor()));
|
||||
wrapper.add(mainBorderWrapper, BorderLayout.CENTER);
|
||||
final JComponent specificDetails = myDetails.create();
|
||||
myDetailsPanel = new GitLogDetailsPanel(myProject, myDetailsCache, new Convertor<VirtualFile, SymbolicRefs>() {
|
||||
@Override
|
||||
public SymbolicRefs convert(VirtualFile o) {
|
||||
return myRefs.get(o);
|
||||
}
|
||||
});
|
||||
final JPanel borderWrapper = new JPanel(new BorderLayout());
|
||||
borderWrapper.setBorder(BorderFactory.createLineBorder(UIUtil.getBorderColor()));
|
||||
borderWrapper.add(specificDetails, BorderLayout.CENTER);
|
||||
borderWrapper.add(myDetailsPanel.getComponent(), BorderLayout.CENTER);
|
||||
|
||||
final Splitter splitter = new Splitter(true, 0.6f);
|
||||
splitter.setFirstComponent(wrapper);
|
||||
@@ -604,7 +689,7 @@ public class GitLogUI implements Disposable {
|
||||
if (rows.length != 1) return;
|
||||
final CommitI commitAt = myTableModel.getCommitAt(rows[0]);
|
||||
if (commitAt == null) return;
|
||||
final GitCommit gitCommit = myDetailsCache.convert(commitAt.selectRepository(myRootsUnderVcs), commitAt.getHash());
|
||||
final GitCommit gitCommit = fullCommitPresentation(commitAt);
|
||||
if (gitCommit == null) return;
|
||||
sink.put(key, gitCommit.getDescription());
|
||||
}
|
||||
@@ -615,7 +700,7 @@ public class GitLogUI implements Disposable {
|
||||
private GitCommit getCommitAtRow(int row) {
|
||||
final CommitI commitAt = myTableModel.getCommitAt(row);
|
||||
if (commitAt == null) return null;
|
||||
final GitCommit gitCommit = myDetailsCache.convert(commitAt.selectRepository(myRootsUnderVcs), commitAt.getHash());
|
||||
final GitCommit gitCommit = fullCommitPresentation(commitAt);
|
||||
if (gitCommit == null) return null;
|
||||
return gitCommit;
|
||||
}
|
||||
@@ -647,20 +732,42 @@ public class GitLogUI implements Disposable {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Pair<String, List<String>> preparse(String previousFilter) {
|
||||
final String[] strings = previousFilter.split("[\\s]");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
mySearchContext.clear();
|
||||
final List<String> words = new ArrayList<String>();
|
||||
for (String string : strings) {
|
||||
if (string.trim().length() == 0) continue;
|
||||
mySearchContext.add(string.toLowerCase());
|
||||
final String word = StringUtil.escapeToRegexp(string);
|
||||
sb.append(word).append(".*");
|
||||
words.add(word);
|
||||
private static class CommentSearchContext {
|
||||
private final List<HighlightingRendererBase> myListeners;
|
||||
private final List<String> mySearchContext;
|
||||
|
||||
private CommentSearchContext() {
|
||||
mySearchContext = new ArrayList<String>();
|
||||
myListeners = new ArrayList<HighlightingRendererBase>();
|
||||
}
|
||||
|
||||
public void addHighlighter(final HighlightingRendererBase renderer) {
|
||||
myListeners.add(renderer);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mySearchContext.clear();
|
||||
for (HighlightingRendererBase listener : myListeners) {
|
||||
listener.setSearchContext(Collections.<String>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
public String preparse(String previousFilter) {
|
||||
final String[] strings = previousFilter.split("[\\s]");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
mySearchContext.clear();
|
||||
for (String string : strings) {
|
||||
if (string.trim().length() == 0) continue;
|
||||
mySearchContext.add(string.toLowerCase());
|
||||
final String word = StringUtil.escapeToRegexp(string);
|
||||
sb.append(word).append(".*");
|
||||
}
|
||||
new SubstringsFilter().doFilter(mySearchContext);
|
||||
for (HighlightingRendererBase listener : myListeners) {
|
||||
listener.setSearchContext(mySearchContext);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
new SubstringsFilter().doFilter(mySearchContext);
|
||||
return new Pair<String, List<String>>(sb.toString(), words);
|
||||
}
|
||||
|
||||
public static class SubstringsFilter extends AbstractFilterChildren<String> {
|
||||
@@ -729,103 +836,17 @@ public class GitLogUI implements Disposable {
|
||||
}
|
||||
};
|
||||
|
||||
private static abstract class HighlightingRendererBase {
|
||||
private final List<String> mySearchContext;
|
||||
|
||||
protected HighlightingRendererBase(List<String> searchContext) {
|
||||
mySearchContext = searchContext;
|
||||
}
|
||||
|
||||
protected abstract void usual(final String s);
|
||||
protected abstract void highlight(final String s);
|
||||
|
||||
void tryHighlight(String text) {
|
||||
final String lower = text.toLowerCase();
|
||||
int idxFrom = 0;
|
||||
while (idxFrom < text.length()) {
|
||||
boolean adjusted = false;
|
||||
int adjustedIdx = text.length() + 1;
|
||||
int adjLen = 0;
|
||||
for (String word : mySearchContext) {
|
||||
final int next = lower.indexOf(word, idxFrom);
|
||||
if ((next != -1) && (adjustedIdx > next)) {
|
||||
adjustedIdx = next;
|
||||
adjLen = word.length();
|
||||
adjusted = true;
|
||||
}
|
||||
}
|
||||
if (adjusted) {
|
||||
if (idxFrom != adjustedIdx) {
|
||||
usual(text.substring(idxFrom, adjustedIdx));
|
||||
}
|
||||
idxFrom = adjustedIdx + adjLen;
|
||||
highlight(text.substring(adjustedIdx, idxFrom));
|
||||
continue;
|
||||
}
|
||||
usual(text.substring(idxFrom));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AuthorRenderer extends ColoredTableCellRenderer {
|
||||
private final SimpleTextAttributes myCurrentUserAttributes;
|
||||
private final SimpleTextAttributes myHighlightAttributes;
|
||||
private final List<String> mySearchContext;
|
||||
private final SimpleTextAttributes myUsualAttributes;
|
||||
protected final HighlightingRendererBase myWorker;
|
||||
|
||||
private AuthorRenderer(SimpleTextAttributes currentUserAttributes,
|
||||
SimpleTextAttributes highlightAttributes,
|
||||
List<String> searchContext,
|
||||
SimpleTextAttributes usualAttributes) {
|
||||
myCurrentUserAttributes = currentUserAttributes;
|
||||
myHighlightAttributes = highlightAttributes;
|
||||
mySearchContext = searchContext;
|
||||
myUsualAttributes = usualAttributes;
|
||||
myWorker = new HighlightingRendererBase(searchContext) {
|
||||
@Override
|
||||
protected void usual(String s) {
|
||||
append(s, myUsualAttributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void highlight(String s) {
|
||||
append(s, myHighlightAttributes);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
|
||||
setBackground(getLogicBackground(selected, row));
|
||||
if (BigTableTableModel.LOADING == value) {
|
||||
return;
|
||||
}
|
||||
final String text = value.toString();
|
||||
|
||||
if (mySearchContext.isEmpty()) {
|
||||
append(text, myUsualAttributes);
|
||||
return;
|
||||
}
|
||||
myWorker.tryHighlight(text);
|
||||
}
|
||||
}
|
||||
|
||||
private class HighLightingRenderer extends ColoredTableCellRenderer {
|
||||
private final SimpleTextAttributes myHighlightAttributes;
|
||||
private final List<String> mySearchContext;
|
||||
private final SimpleTextAttributes myUsualAttributes;
|
||||
private SimpleTextAttributes myUsualAttributesForRun;
|
||||
protected final HighlightingRendererBase myWorker;
|
||||
|
||||
public HighLightingRenderer(SimpleTextAttributes highlightAttributes, SimpleTextAttributes usualAttributes,
|
||||
final List<String> searchContext) {
|
||||
public HighLightingRenderer(SimpleTextAttributes highlightAttributes, SimpleTextAttributes usualAttributes) {
|
||||
myHighlightAttributes = highlightAttributes;
|
||||
mySearchContext = searchContext;
|
||||
myUsualAttributes = usualAttributes == null ? SimpleTextAttributes.REGULAR_ATTRIBUTES : usualAttributes;
|
||||
myUsualAttributesForRun = myUsualAttributes;
|
||||
myWorker = new HighlightingRendererBase(searchContext) {
|
||||
myWorker = new HighlightingRendererBase() {
|
||||
@Override
|
||||
protected void usual(String s) {
|
||||
append(s, myUsualAttributesForRun);
|
||||
@@ -838,6 +859,10 @@ public class GitLogUI implements Disposable {
|
||||
};
|
||||
}
|
||||
|
||||
public HighlightingRendererBase getWorker() {
|
||||
return myWorker;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeCellRenderer(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
|
||||
setBackground(getLogicBackground(selected, row));
|
||||
@@ -847,7 +872,7 @@ public class GitLogUI implements Disposable {
|
||||
final String text = value.toString();
|
||||
myUsualAttributesForRun = isCurrentUser(row, text) ?
|
||||
SimpleTextAttributes.merge(myUsualAttributes, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES) : myUsualAttributes;
|
||||
if (mySearchContext.isEmpty()) {
|
||||
if (myWorker.isEmpty()) {
|
||||
append(text, myUsualAttributesForRun);
|
||||
return;
|
||||
}
|
||||
@@ -931,12 +956,7 @@ public class GitLogUI implements Disposable {
|
||||
CaptionIcon.Form.SQUARE, plus, branch.equals(commit.getCurrentBranch()));
|
||||
myBranchMap.put(branch, icon);
|
||||
}
|
||||
myCurrentWidth = icon.getIconWidth();
|
||||
myPanel.removeAll();
|
||||
myPanel.setBackground(getLogicBackground(isSelected, row));
|
||||
myPanel.add(new JLabel(icon));
|
||||
myInner.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
myPanel.add(myInner);
|
||||
addOneIcon(table, value, isSelected, hasFocus, row, column, icon);
|
||||
return myPanel;
|
||||
}
|
||||
if ((localSize + remoteSize == 0) && (tagsSize > 0)) {
|
||||
@@ -947,12 +967,7 @@ public class GitLogUI implements Disposable {
|
||||
tag, table, CaptionIcon.Form.ROUNDED, tagsSize > 1, false);
|
||||
myTagMap.put(tag, icon);
|
||||
}
|
||||
myCurrentWidth = icon.getIconWidth();
|
||||
myPanel.removeAll();
|
||||
myPanel.setBackground(getLogicBackground(isSelected, row));
|
||||
myPanel.add(new JLabel(icon));
|
||||
myInner.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
myPanel.add(myInner);
|
||||
addOneIcon(table, value, isSelected, hasFocus, row, column, icon);
|
||||
return myPanel;
|
||||
}
|
||||
}
|
||||
@@ -960,12 +975,21 @@ public class GitLogUI implements Disposable {
|
||||
return myInner;
|
||||
}
|
||||
|
||||
private void addOneIcon(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column, Icon icon) {
|
||||
myCurrentWidth = icon.getIconWidth();
|
||||
myPanel.removeAll();
|
||||
myPanel.setBackground(getLogicBackground(isSelected, row));
|
||||
myPanel.add(new JLabel(icon));
|
||||
myInner.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
myPanel.add(myInner);
|
||||
}
|
||||
|
||||
private class Inner extends HighLightingRenderer {
|
||||
private final IssueLinkRenderer myIssueLinkRenderer;
|
||||
private final Consumer<String> myConsumer;
|
||||
|
||||
private Inner() {
|
||||
super(HIGHLIGHT_TEXT_ATTRIBUTES, null, mySearchContext);
|
||||
super(HIGHLIGHT_TEXT_ATTRIBUTES, null);
|
||||
myIssueLinkRenderer = new IssueLinkRenderer(myProject, this);
|
||||
myConsumer = new Consumer<String>() {
|
||||
@Override
|
||||
@@ -992,10 +1016,8 @@ public class GitLogUI implements Disposable {
|
||||
Color bkgColor;
|
||||
final CommitI commitAt = myTableModel.getCommitAt(row);
|
||||
GitCommit gitCommit = null;
|
||||
VirtualFile root = null;
|
||||
if (commitAt != null & (! commitAt.holdsDecoration())) {
|
||||
root = commitAt.selectRepository(myRootsUnderVcs);
|
||||
gitCommit = myDetailsCache.convert(root, commitAt.getHash());
|
||||
if (commitAt != null && (! commitAt.holdsDecoration())) {
|
||||
gitCommit = fullCommitPresentation(commitAt);
|
||||
}
|
||||
|
||||
if (isSelected) {
|
||||
@@ -1003,7 +1025,7 @@ public class GitLogUI implements Disposable {
|
||||
} else {
|
||||
bkgColor = UIUtil.getTableBackground();
|
||||
if (gitCommit != null) {
|
||||
if (myDetailsCache.getStashName(root, gitCommit.getShortHash()) != null) {
|
||||
if (myDetailsCache.getStashName(commitAt.selectRepository(myRootsUnderVcs), gitCommit.getShortHash()) != null) {
|
||||
bkgColor = Colors.stashed;
|
||||
} else if (gitCommit.isOnLocal() && gitCommit.isOnTracked()) {
|
||||
bkgColor = Colors.commonThisBranch;
|
||||
@@ -1019,9 +1041,6 @@ public class GitLogUI implements Disposable {
|
||||
|
||||
private void initAuthor() {
|
||||
AUTHOR = new ColumnInfo<Object, String>("Author") {
|
||||
private final TableCellRenderer myRenderer = new HighLightingRenderer(HIGHLIGHT_TEXT_ATTRIBUTES,
|
||||
SimpleTextAttributes.REGULAR_ATTRIBUTES, myUsersSearchContext);
|
||||
|
||||
@Override
|
||||
public String valueOf(Object o) {
|
||||
if (o instanceof GitCommit) {
|
||||
@@ -1032,7 +1051,7 @@ public class GitLogUI implements Disposable {
|
||||
|
||||
@Override
|
||||
public TableCellRenderer getRenderer(Object o) {
|
||||
return myRenderer;
|
||||
return myAuthorRenderer;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1096,7 +1115,7 @@ public class GitLogUI implements Disposable {
|
||||
final Collection<String> startingPoints = mySelectedBranch == null ? Collections.<String>emptyList() : Collections.singletonList(mySelectedBranch);
|
||||
myDescriptionRenderer.resetIcons();
|
||||
final boolean commentFilterEmpty = StringUtil.isEmptyOrSpaces(myPreviousFilter);
|
||||
mySearchContext.clear();
|
||||
myCommentSearchContext.clear();
|
||||
myUsersSearchContext.clear();
|
||||
|
||||
if (commentFilterEmpty && (myUserFilterI.myFilter == null)) {
|
||||
@@ -1105,9 +1124,8 @@ public class GitLogUI implements Disposable {
|
||||
} else {
|
||||
ChangesFilter.Comment comment = null;
|
||||
if (! commentFilterEmpty) {
|
||||
final Pair<String, List<String>> preparse = preparse(myPreviousFilter);
|
||||
final String first = preparse.getFirst();
|
||||
comment = new ChangesFilter.Comment(first);
|
||||
final String commentFilter = myCommentSearchContext.preparse(myPreviousFilter);
|
||||
comment = new ChangesFilter.Comment(commentFilter);
|
||||
}
|
||||
Set<ChangesFilter.Filter> userFilters = null;
|
||||
if (myUserFilterI.myFilter != null) {
|
||||
@@ -1127,13 +1145,14 @@ public class GitLogUI implements Disposable {
|
||||
myMediator.reload(new RootsHolder(myRootsUnderVcs), startingPoints, new GitLogFilters(comment, userFilters, null,
|
||||
possibleReferencies));
|
||||
}
|
||||
myCommentSearchContext.addHighlighter(myDetailsPanel.getHtmlHighlighter());
|
||||
updateMoreVisibility();
|
||||
selectionChanged();
|
||||
mySelectionRequestsMerger.request();
|
||||
fireTableRepaint();
|
||||
myTableModel.fireTableRowsDeleted(0, was);
|
||||
}
|
||||
|
||||
private interface Colors {
|
||||
interface Colors {
|
||||
Color tag = new Color(241, 239, 158);
|
||||
Color remote = new Color(188,188,252);
|
||||
Color local = new Color(117,238,199);
|
||||
@@ -1142,147 +1161,6 @@ public class GitLogUI implements Disposable {
|
||||
Color stashed = new Color(225,225,225);
|
||||
}
|
||||
|
||||
private class MySpecificDetails {
|
||||
private JEditorPane myJEditorPane;
|
||||
private JPanel myMarksPanel;
|
||||
private BoxLayout myBoxLayout;
|
||||
private final Project myProject;
|
||||
private boolean myMissingBranchesInfo;
|
||||
|
||||
private MySpecificDetails(final Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
public JComponent create() {
|
||||
myJEditorPane = new JEditorPane(UIUtil.HTML_MIME, "");
|
||||
myJEditorPane.setPreferredSize(new Dimension(150, 100));
|
||||
myJEditorPane.setEditable(false);
|
||||
myJEditorPane.setBackground(UIUtil.getComboBoxDisabledBackground());
|
||||
myJEditorPane.addHyperlinkListener(new BrowserHyperlinkListener());
|
||||
myMarksPanel = new JPanel();
|
||||
myBoxLayout = new BoxLayout(myMarksPanel, BoxLayout.X_AXIS);
|
||||
myMarksPanel.setLayout(myBoxLayout);
|
||||
final JPanel wrapper = new JPanel(new BorderLayout());
|
||||
wrapper.add(myMarksPanel, BorderLayout.NORTH);
|
||||
wrapper.add(myJEditorPane, BorderLayout.CENTER);
|
||||
final Color color = UIUtil.getTableBackground();
|
||||
myJEditorPane.setBackground(color);
|
||||
wrapper.setBackground(color);
|
||||
myMarksPanel.setBackground(color);
|
||||
final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(wrapper);
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public void putBranches(VirtualFile root, final GitCommit commit, final List<String> branches) {
|
||||
myMissingBranchesInfo = branches == null;
|
||||
myJEditorPane.setText(parseDetails(root, commit, branches));
|
||||
}
|
||||
|
||||
public boolean isMissingBranchesInfo() {
|
||||
return myMissingBranchesInfo;
|
||||
}
|
||||
|
||||
public void refresh(VirtualFile root, final GitCommit commit) {
|
||||
if (commit == null) {
|
||||
myJEditorPane.setText("");
|
||||
myMarksPanel.removeAll();
|
||||
myMissingBranchesInfo = false;
|
||||
} else {
|
||||
final List<String> branches = myDetailsCache.getBranches(root, commit.getShortHash());
|
||||
myMissingBranchesInfo = branches == null;
|
||||
final Font font = myJEditorPane.getFont().deriveFont((float) (myJEditorPane.getFont().getSize() - 1));
|
||||
final String currentBranch = commit.getCurrentBranch();
|
||||
myMarksPanel.removeAll();
|
||||
for (String s : commit.getLocalBranches()) {
|
||||
myMarksPanel.add(new JLabel(new CaptionIcon(Colors.local, font, s, myMarksPanel, CaptionIcon.Form.SQUARE, false,
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
for (String s : commit.getRemoteBranches()) {
|
||||
myMarksPanel.add(new JLabel(new CaptionIcon(Colors.remote, font, s, myMarksPanel, CaptionIcon.Form.SQUARE, false,
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
for (String s : commit.getTags()) {
|
||||
myMarksPanel.add(new JLabel(new CaptionIcon(Colors.tag, font, s, myMarksPanel, CaptionIcon.Form.ROUNDED, false,
|
||||
s.equals(currentBranch))));
|
||||
}
|
||||
myMarksPanel.repaint();
|
||||
myJEditorPane.setText(parseDetails(root, commit, branches));
|
||||
}
|
||||
}
|
||||
|
||||
private String parseDetails(VirtualFile root, final GitCommit c, final List<String> branches) {
|
||||
final String hash = new HtmlHighlighter(c.getHash().getValue()).getResult();
|
||||
final String author = new HtmlHighlighter(c.getAuthor()).getResult();
|
||||
final String committer = new HtmlHighlighter(c.getCommitter()).getResult();
|
||||
final String comment = IssueLinkHtmlRenderer.formatTextWithLinks(myProject, c.getDescription(),
|
||||
new Convertor<String, String>() {
|
||||
@Override
|
||||
public String convert(String o) {
|
||||
return new HtmlHighlighter(o).getResult();
|
||||
}
|
||||
});
|
||||
|
||||
final StringBuilder sb = new StringBuilder().append("<html><head>").append(UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()))
|
||||
.append("</head><body><table>");
|
||||
final String stashName = myDetailsCache.getStashName(root, c.getShortHash());
|
||||
if (! StringUtil.isEmptyOrSpaces(stashName)) {
|
||||
sb.append("<tr valign=\"top\"><td><b>").append(stashName).append("</b></td><td></td></tr>");
|
||||
}
|
||||
sb.append("<tr valign=\"top\"><td><i>Hash:</i></td><td>").append(
|
||||
hash).append("</td></tr>" + "<tr valign=\"top\"><td><i>Author:</i></td><td>")
|
||||
.append(author).append(" (").append(c.getAuthorEmail()).append(") <i>at</i> ")
|
||||
.append(DateFormatUtil.formatPrettyDateTime(c.getAuthorTime()))
|
||||
.append("</td></tr>" + "<tr valign=\"top\"><td><i>Commiter:</i></td><td>")
|
||||
.append(committer).append(" (").append(c.getComitterEmail()).append(") <i>at</i> ")
|
||||
.append(DateFormatUtil.formatPrettyDateTime(c.getDate())).append(
|
||||
"</td></tr>" + "<tr valign=\"top\"><td><i>Description:</i></td><td><b>")
|
||||
.append(comment).append("</b></td></tr>");
|
||||
sb.append("<tr valign=\"top\"><td><i>Contained in branches:<i></td><td>");
|
||||
if (branches != null && (! branches.isEmpty())) {
|
||||
for (int i = 0; i < branches.size(); i++) {
|
||||
String s = branches.get(i);
|
||||
sb.append(s);
|
||||
if (i + 1 < branches.size()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
} else if (branches != null && branches.isEmpty()) {
|
||||
sb.append("<font color=gray><no branches></font>");
|
||||
} else {
|
||||
sb.append("<font color=gray>Loading...</font>");
|
||||
}
|
||||
sb.append("</td></tr>");
|
||||
sb.append("</table></body></html>");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private class HtmlHighlighter extends HighlightingRendererBase {
|
||||
private final String myText;
|
||||
private final StringBuilder mySb;
|
||||
|
||||
private HtmlHighlighter(String text) {
|
||||
super(mySearchContext);
|
||||
myText = text;
|
||||
mySb = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void highlight(String s) {
|
||||
mySb.append("<font color=rgb(255,128,0)>").append(s).append("</font>");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void usual(String s) {
|
||||
mySb.append(s);
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
tryHighlight(myText);
|
||||
return mySb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private class MyCherryPick extends DumbAwareAction {
|
||||
private final Set<AbstractHash> myIdsInProgress;
|
||||
|
||||
|
||||
@@ -69,4 +69,24 @@ public class GroupHeaderCommitDecorator implements CommitI {
|
||||
public CommitI getDelegate() {
|
||||
return myDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GroupHeaderCommitDecorator that = (GroupHeaderCommitDecorator)o;
|
||||
|
||||
if (!myDecoration.equals(that.myDecoration)) return false;
|
||||
if (!myDelegate.equals(that.myDelegate)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myDecoration.hashCode();
|
||||
result = 31 * result + myDelegate.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,4 +61,24 @@ public class GroupHeaderDatePseudoCommit implements CommitI {
|
||||
@Override
|
||||
public void setWireNumber(int wireNumber) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GroupHeaderDatePseudoCommit that = (GroupHeaderDatePseudoCommit)o;
|
||||
|
||||
if (myTime != that.myTime) return false;
|
||||
if (!myGroupName.equals(that.myGroupName)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int)(myTime ^ (myTime >>> 32));
|
||||
result = 31 * result + myGroupName.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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 git4idea.history.wholeTree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author irengrig
|
||||
* Date: 7/1/11
|
||||
* Time: 2:37 PM
|
||||
*/
|
||||
abstract class HighlightingRendererBase {
|
||||
private final List<String> mySearchContext;
|
||||
|
||||
HighlightingRendererBase() {
|
||||
mySearchContext = new ArrayList<String>();
|
||||
}
|
||||
|
||||
public void setSearchContext(final List<String> list) {
|
||||
mySearchContext.clear();
|
||||
mySearchContext.addAll(list);
|
||||
}
|
||||
|
||||
protected abstract void usual(final String s);
|
||||
protected abstract void highlight(final String s);
|
||||
|
||||
void tryHighlight(String text) {
|
||||
final String lower = text.toLowerCase();
|
||||
int idxFrom = 0;
|
||||
while (idxFrom < text.length()) {
|
||||
boolean adjusted = false;
|
||||
int adjustedIdx = text.length() + 1;
|
||||
int adjLen = 0;
|
||||
for (String word : mySearchContext) {
|
||||
final int next = lower.indexOf(word, idxFrom);
|
||||
if ((next != -1) && (adjustedIdx > next)) {
|
||||
adjustedIdx = next;
|
||||
adjLen = word.length();
|
||||
adjusted = true;
|
||||
}
|
||||
}
|
||||
if (adjusted) {
|
||||
if (idxFrom != adjustedIdx) {
|
||||
usual(text.substring(idxFrom, adjustedIdx));
|
||||
}
|
||||
idxFrom = adjustedIdx + adjLen;
|
||||
highlight(text.substring(adjustedIdx, idxFrom));
|
||||
continue;
|
||||
}
|
||||
usual(text.substring(idxFrom));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return mySearchContext == null || mySearchContext.isEmpty();
|
||||
}
|
||||
}
|
||||
+20
@@ -65,4 +65,24 @@ public class MultipleRepositoryCommitDecorator implements CommitI {
|
||||
public <T> T selectRepository(List<T> repositories) {
|
||||
return repositories.get(myRepositoryIdx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
MultipleRepositoryCommitDecorator that = (MultipleRepositoryCommitDecorator)o;
|
||||
|
||||
if (myRepositoryIdx != that.myRepositoryIdx) return false;
|
||||
if (!myDelegate.equals(that.myDelegate)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myDelegate.hashCode();
|
||||
result = 31 * result + myRepositoryIdx;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,4 +64,24 @@ public class WireNumberCommitDecoration implements CommitI {
|
||||
public void setWireNumber(int wireNumber) {
|
||||
myWireNumber = wireNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
WireNumberCommitDecoration that = (WireNumberCommitDecoration)o;
|
||||
|
||||
if (myWireNumber != that.myWireNumber) return false;
|
||||
if (!myDelegate.equals(that.myDelegate)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myDelegate.hashCode();
|
||||
result = 31 * result + myWireNumber;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user