/*
* CommitListTable.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.studio.client.workbench.views.vcs.dialog;
import com.google.gwt.cell.client.AbstractSafeHtmlCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.text.shared.SafeHtmlRenderer;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.TextColumn;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import org.rstudio.core.client.SafeHtmlUtil;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.js.JsUtil;
import org.rstudio.core.client.theme.RStudioCellTableStyle;
import org.rstudio.core.client.widget.MultiSelectCellTable;
import org.rstudio.studio.client.workbench.views.vcs.dialog.HistoryPanel.Styles;
import org.rstudio.studio.client.workbench.views.vcs.dialog.HistoryPresenter.CommitListDisplay;
import org.rstudio.studio.client.workbench.views.vcs.dialog.graph.GraphLine;
import org.rstudio.studio.client.workbench.views.vcs.dialog.graph.GraphTheme;
import java.util.List;
public class CommitListTable extends MultiSelectCellTable<CommitInfo>
implements CommitListDisplay
{
interface Resources extends CellTable.Resources
{
@Override
@Source({RStudioCellTableStyle.RSTUDIO_DEFAULT_CSS, "CommitListTableCellTableStyle.css"})
Style cellTableStyle();
}
interface CommitListTableCellTableStyle extends CellTable.Style
{
}
private static class CommitColumn extends Column<CommitInfo, CommitInfo>
{
private static class RenderCell extends AbstractSafeHtmlCell<CommitInfo>
{
private RenderCell(SafeHtmlRenderer<CommitInfo> commitInfoSafeHtmlRenderer,
String... consumedEvents)
{
super(commitInfoSafeHtmlRenderer, consumedEvents);
}
@Override
protected void render(Context context, SafeHtml data, SafeHtmlBuilder sb)
{
if (data != null)
sb.append(data);
}
}
private CommitColumn(SafeHtmlRenderer<CommitInfo> renderer)
{
super(new RenderCell(renderer));
}
@Override
public CommitInfo getValue(CommitInfo object)
{
return object;
}
}
@SuppressWarnings("unused")
private class GraphAndSubjectRenderer implements SafeHtmlRenderer<CommitInfo>
{
private GraphAndSubjectRenderer(GraphTheme theme)
{
graphRenderer_ = new GraphRenderer(theme);
subjectRenderer_ = new SubjectRenderer();
}
@Override
public SafeHtml render(CommitInfo object)
{
return SafeHtmlUtil.concat(graphRenderer_.render(object),
subjectRenderer_.render(object));
}
@Override
public void render(CommitInfo object, SafeHtmlBuilder builder)
{
builder.append(render(object));
}
private final GraphRenderer graphRenderer_;
private final SubjectRenderer subjectRenderer_;
}
private class GraphRenderer implements SafeHtmlRenderer<CommitInfo>
{
public GraphRenderer(GraphTheme theme)
{
theme_ = theme;
}
@Override
public SafeHtml render(CommitInfo object)
{
if (lastGraphImg_ != null && object.getGraph().equals(lastGraph_))
return lastGraphImg_;
lastGraph_ = object.getGraph();
if (object.getGraph().length() == 0)
return lastGraphImg_ = SafeHtmlUtil.createEmpty();
return lastGraphImg_ = new GraphLine(object.getGraph()).render(theme_);
}
@Override
public void render(CommitInfo object, SafeHtmlBuilder builder)
{
builder.append(render(object));
}
private final GraphTheme theme_;
private String lastGraph_ = "";
private SafeHtml lastGraphImg_;
}
private class SubjectRenderer implements SafeHtmlRenderer<CommitInfo>
{
@Override
public SafeHtml render(CommitInfo commit)
{
SafeHtmlBuilder builder = new SafeHtmlBuilder();
for (String ref : JsUtil.asIterable(commit.getRefs()))
{
String style = styles_.ref();
if (ref.startsWith("refs/heads/"))
{
ref = ref.substring("refs/heads/".length());
style += " " + styles_.branch();
}
else if (ref.startsWith("refs/remotes/"))
{
ref = ref.substring("refs/remotes/".length());
style += " " + styles_.remote();
}
else if (ref.equals("HEAD"))
{
style += " " + styles_.head();
}
SafeHtmlUtil.appendSpan(builder, style, ref);
}
for (String tag : JsUtil.asIterable(commit.getTags()))
{
if (tag.startsWith("refs/tags/"))
tag = tag.substring("refs/tags/".length());
SafeHtmlUtil.appendSpan(builder, styles_.tag(), tag);
}
builder.appendEscaped(commit.getSubject());
return builder.toSafeHtml();
}
@Override
public void render(CommitInfo object, SafeHtmlBuilder builder)
{
builder.append(render(object));
}
}
public CommitListTable(Styles styles, String idColName)
{
super(100,
GWT.<Resources>create(Resources.class));
styles_ = styles;
graphTheme_ = new GraphTheme(styles.graphLineImg());
graphCol_ = new CommitColumn(new GraphRenderer(graphTheme_));
addColumn(graphCol_);
CommitColumn subjectCol = new CommitColumn(new SubjectRenderer());
addColumn(subjectCol, "Subject");
TextColumn<CommitInfo> authorCol = new TextColumn<CommitInfo>()
{
@Override
public String getValue(CommitInfo object)
{
return object.getAuthor();
}
};
addColumn(authorCol, "Author");
TextColumn<CommitInfo> dateCol = new TextColumn<CommitInfo>()
{
@Override
public String getValue(CommitInfo object)
{
return DateTimeFormat.getFormat(
PredefinedFormat.DATE_SHORT).format(object.getDate());
}
};
addColumn(dateCol, "Date");
TextColumn<CommitInfo> idCol = new TextColumn<CommitInfo>()
{
@Override
public String getValue(CommitInfo object)
{
return object.getId();
}
};
addColumn(idCol, idColName);
setColumnWidth(graphCol_, "0");
setColumnWidth(idCol, "100px");
setColumnWidth(subjectCol, "67%");
setColumnWidth(authorCol, "33%");
setColumnWidth(dateCol, "100px");
selectionModel_ = new SingleSelectionModel<CommitInfo>();
setSelectionModel(selectionModel_);
}
private void updateGraphColumnWidth()
{
int width = 0;
for (CommitInfo commit : getVisibleItems())
{
if (!StringUtil.isNullOrEmpty(commit.getGraph()))
{
width = Math.max(
width,
new GraphLine(commit.getGraph()).getTotalWidth(graphTheme_));
}
}
if (width > 0)
setColumnWidth(graphCol_, (width + 12) + "px");
else
setColumnWidth(graphCol_, "0");
}
@Override
public void setRowData(int start, List<? extends CommitInfo> values)
{
if (selectionModel_.getSelectedObject() != null)
{
selectionModel_.setSelected(selectionModel_.getSelectedObject(),
false);
}
super.setRowData(start, values);
updateGraphColumnWidth();
maybePreselectFirstRow();
}
private void maybePreselectFirstRow()
{
if (!autoSelectFirstRow_)
return;
Scheduler.get().scheduleDeferred(new ScheduledCommand()
{
@Override
public void execute()
{
if (getVisibleItemCount() > 0
&& (selectionModel_.getSelectedObject() == null ||
selectionModel_.getSelectedObject().getId().equals(getVisibleItem(0).getId())))
{
selectionModel_.setSelected(getVisibleItem(0), true);
}
}
});
}
public HandlerRegistration addSelectionChangeHandler(SelectionChangeEvent.Handler handler)
{
return selectionModel_.addSelectionChangeHandler(handler);
}
@Override
public CommitInfo getSelectedCommit()
{
return selectionModel_.getSelectedObject();
}
@Override
public void clearSelection()
{
if (selectionModel_.getSelectedObject() != null)
selectionModel_.setSelected(selectionModel_.getSelectedObject(),
false);
}
@Override
public void setAutoSelectFirstRow(boolean autoSelect)
{
autoSelectFirstRow_ = autoSelect;
}
private final SingleSelectionModel<CommitInfo> selectionModel_;
private final Styles styles_;
private CommitColumn graphCol_;
private GraphTheme graphTheme_;
private boolean autoSelectFirstRow_ = true;
}