/*
* Copyright 2013 Hewlett-Packard Development Company, L.P
*
* 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.hp.alm.ali.idea.ui;
import com.hp.alm.ali.idea.impl.GotoFileModel;
import com.hp.alm.ali.idea.rest.RestService;
import com.hp.alm.ali.idea.ui.event.KeyboardStateFollower;
import com.hp.alm.ali.idea.model.Entity;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.util.EditSourceUtil;
import com.intellij.ide.util.gotoByName.ChooseByNameModel;
import com.intellij.navigation.NavigationItem;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.ui.components.labels.LinkLabel;
import com.intellij.ui.components.labels.LinkListener;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.List;
import java.util.regex.Pattern;
public class ChangesetPanel extends JPanel {
public static final String OPERATION_ADDED = "Added";
public static final String OPERATION_MODIFIED = "Modified";
public static final String OPERATION_REMOVED = "Removed";
private Project project;
private RestService restService;
private String revStr;
private String descStr;
private String ownerStr;
private boolean descriptionFilter;
public ChangesetPanel(Project project, Entity changeset, boolean descriptionFilter) {
this.project = project;
this.descriptionFilter = descriptionFilter;
restService = project.getComponent(RestService.class);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setAlignmentX(LEFT_ALIGNMENT);
JPanel header = new JPanel();
header.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK), BorderFactory.createEmptyBorder(5, 0, 0, 0)));
header.setLayout(new GridBagLayout());
header.setBackground(Color.WHITE);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.fill = GridBagConstraints.HORIZONTAL;
revStr = changeset.getPropertyValue("rev");
JLabel revision = new FixedLabel("Rev. "+ revStr, 50);
revision.setHorizontalAlignment(JLabel.LEFT);
revision.setForeground(Color.GRAY);
c.weightx = 0.2;
header.add(revision, c);
c.gridx++;
descStr = changeset.getPropertyValue("description");
JLabel description = new FixedLabel(descStr, 250);
c.weightx = 0.6;
header.add(description, c);
c.gridx++;
ownerStr = changeset.getPropertyValue("owner");
JLabel author = new FixedLabel(ownerStr, 180);
author.setFont(author.getFont().deriveFont(Font.BOLD));
c.weightx = 0.2;
header.add(author, c);
c.gridx++;
JLabel date = new FixedLabel(changeset.getPropertyValue("date"), 140);
c.weightx = 0.0;
header.add(date);
add(header);
}
private boolean matches(String filter) {
if(filter == null) {
return true;
}
if(containsIgnoreCase(ownerStr, filter) || containsIgnoreCase(revStr, filter)) {
return true;
}
if(descriptionFilter && containsIgnoreCase(descStr, filter)) {
return true;
}
return false;
}
private boolean containsIgnoreCase(String str, String substr) {
return Pattern.compile(Pattern.quote(substr), Pattern.CASE_INSENSITIVE).matcher(str).find();
}
public void addFiles(List<Entity> files, String filter) {
boolean matches = matches(filter);
for(final Entity file: files) {
final String filePath = file.getPropertyValue("path");
if(!matches && !containsIgnoreCase(filePath, filter)) {
continue;
}
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0));
panel.setBackground(Color.WHITE);
final String operationFull = file.getPropertyValue("operation");
String operation = operationFull.substring(0, 1);
if("FILE".equals(file.getPropertyValue("file-type")) && (OPERATION_MODIFIED.equals(operationFull) || OPERATION_ADDED.equals(operationFull))) { // TODO: support replace
LinkLabel action = new LinkLabel("["+ operation +"]", null);
action.setListener(new LinkListener() {
@Override
public void linkSelected(LinkLabel aSource, Object aLinkData) {
if(file.getPropertyValue("diff-link").isEmpty() || KeyboardStateFollower.getState().isShiftDown()) {
restService.launchProjectUrl("scm/file-diff?file=" + file.getId());
} else {
BrowserUtil.launchBrowser(file.getPropertyValue("diff-link"));
}
}
}, null);
panel.add(action);
} else {
panel.add(new JLabel("["+ operation +"]"));
}
LinkLabel path = new LinkLabel(filePath, null);
path.setListener(new LinkListener() {
@Override
public void linkSelected(LinkLabel aSource, Object aLinkData) {
if(!KeyboardStateFollower.getState().isCtrlDown() && !KeyboardStateFollower.getState().isShiftDown()) {
String fileName = filePath.replaceFirst(".*[/\\\\]", "");
ChooseByNameModel gotoFileModel = GotoFileModel.getGotoFileModel(project);
Object[] elems = gotoFileModel.getElementsByName(fileName, false, fileName);
// out of the many possibilities, take the one with longest match (better idea?)
// try to figure out actual mapping is probably too difficult
String filePathReverted = new StringBuffer(filePath).reverse().toString();
Object chosenElem = null;
int longestMatch = 0;
for(Object elem: elems) {
String fullNameReverted = new StringBuffer(gotoFileModel.getFullName(elem)).reverse().toString();
int match = prefixLength(fullNameReverted, filePathReverted);
if(chosenElem == null || match > longestMatch) {
chosenElem = elem;
longestMatch = match;
}
}
if(chosenElem instanceof NavigationItem) {
EditSourceUtil.navigate((NavigationItem)chosenElem, true, true);
return;
}
}
if(!file.getPropertyValue("file-link").isEmpty() && !KeyboardStateFollower.getState().isShiftDown()) {
BrowserUtil.launchBrowser(file.getPropertyValue("file-link"));
} else if(OPERATION_REMOVED.equals(operationFull)) {
Messages.showInfoMessage("Couldn't locate file in the project.", "Not Available");
} else {
restService.launchProjectUrl("scm/file-view?file=" + file.getId());
}
}
}, null);
panel.add(path);
JLabel branch = new JLabel(file.getPropertyValue("branch"));
panel.add(branch);
add(panel);
}
revalidate();
repaint();
}
private int prefixLength(String str1, String str2) {
int len1 = str1.length();
int len2 = str2.length();
int i;
for(i = 0; i < len1 && i < len2; i++) {
if(str1.charAt(i) != str2.charAt(i)) {
break;
}
}
return i;
}
public Dimension getMaximumSize() {
return getPreferredSize();
}
}