blob: 8b222bd2c66804b3332d03f01a619e7ad94917e1 [file] [log] [blame]
/****************************************************************
* Licensed to the Apache Software Foundation (ASF) under one *
* or more contributor license agreements. See the NOTICE file *
* distributed with this work for additional information *
* regarding copyright ownership. The ASF licenses this file *
* to you 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 org.apache.hupa.client.ui;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.apache.hupa.client.HupaConstants;
import org.apache.hupa.client.HupaController;
import org.apache.hupa.client.activity.ToolBarActivity;
import org.apache.hupa.client.bundles.HupaImageBundle;
import org.apache.hupa.client.place.FolderPlace;
import org.apache.hupa.client.place.MessagePlace;
import org.apache.hupa.client.rf.HupaRequestFactory;
import org.apache.hupa.shared.data.MessageImpl.IMAPFlag;
import org.apache.hupa.shared.domain.FetchMessagesResult;
import org.apache.hupa.shared.domain.Message;
import org.apache.hupa.shared.events.MessageListRangeChangedEvent;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.DateCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.ImageResourceCell;
import com.google.gwt.cell.client.SafeHtmlCell;
import com.google.gwt.cell.client.ValueUpdater;
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.dom.client.Style.Unit;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.place.shared.Place;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortEvent.AsyncHandler;
import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.cellview.client.Header;
import com.google.gwt.user.cellview.client.RowStyles;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.Range;
import com.google.inject.Inject;
public class MessagesCellTable extends DataGrid<Message> {
@Inject private ToolBarActivity.Displayable toolBar;
@Inject protected HupaController hc;
@Inject EventBus eventBus;
private String folderName;
private String searchValue;
public static final int PAGE_SIZE = 100;
private HupaImageBundle imageBundle;
CheckboxColumn checkboxCol = new CheckboxColumn();
Column<Message, ?> fromCol;
Column<Message, ?> subjectCol;
Column<Message, ?> attachedCol;
Column<Message, ?> dateCol;
public interface Resources extends DataGrid.Resources {
Resources INSTANCE = GWT.create(Resources.class);
@Source("res/CssMessagesCellTable.css")
CustomStyle dataGridStyle();
}
public interface CustomStyle extends Style {
String fontBold();
String fontNormal();
}
public CheckboxColumn getCheckboxCol() {
return checkboxCol;
}
public final ProvidesKey<Message> KEY_PROVIDER = new ProvidesKey<Message>() {
@Override
public Object getKey(Message item) {
return item == null ? null : item.getUid();
}
};
private final MultiSelectionModel<? super Message> selectionModel = new MultiSelectionModel<Message>(KEY_PROVIDER);
PlaceController pc;
HupaRequestFactory rf;
protected MessageListDataProvider dataProvider;
public class MessageListDataProvider extends AsyncDataProvider<Message> implements HasRefresh {
HasData<Message> display;
@Override
public void addDataDisplay(HasData<Message> display) {
super.addDataDisplay(display);
this.display = display;
}
@Override
public void refresh() {
this.onRangeChanged(display);
}
public void setFechMessagesResult(FetchMessagesResult response) {
if (response == null || response.getRealCount() == 0) {
updateRowCount(-1, true);
} else {
final List<Message> messages = response.getMessages();
updateRowCount(response.getRealCount(), true);
updateRowData(display.getVisibleRange().getStart(), messages);
getColumnSortList().push(dateCol);
}
}
@Override
protected void onRangeChanged(final HasData<Message> display) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
public void execute() {
eventBus.fireEvent(new MessageListRangeChangedEvent(
display.getVisibleRange().getStart(),
display.getVisibleRange().getLength(),
searchValue));
}
});
}
}
public void setSearchValue(String searchValue) {
this.searchValue = searchValue;
}
public final class CheckboxHeader extends Header<Boolean> {
private final MultiSelectionModel<? super Message> selectionModel;
private final AsyncDataProvider<Message> provider;
public CheckboxHeader(MultiSelectionModel<? super Message> selectionModel, AsyncDataProvider<Message> provider) {
super(new CheckboxCell());
this.selectionModel = selectionModel;
this.provider = provider;
}
@Override
public Boolean getValue() {
if (selectionModel == null || provider == null) {
return false;
}
if (selectionModel.getSelectedSet().size() == 0 || provider.getDataDisplays().size() == 0) {
return false;
}
boolean allItemsSelected = selectionModel.getSelectedSet().size() == provider.getDataDisplays().size();
return allItemsSelected;
}
// @Override
// public void onBrowserEvent(Context context, Element elem, NativeEvent event) {
// InputElement input = elem.getFirstChild().cast();
// Boolean isChecked = input.isChecked();
// List<Message> displayedItems = MessagesCellTable.this.getVisibleItems();
// for (Message element : displayedItems) {
// selectionModel.setSelected(element, isChecked);
// checkboxCol.getFieldUpdater().update(0, element, isChecked);
// }
// }
}
@Override
protected void onAttach() {
super.onAttach();
if (dataProvider == null) {
dataProvider = new MessageListDataProvider();
dataProvider.addDataDisplay(this);
}
}
@Inject
public MessagesCellTable(final HupaImageBundle imageBundle, final HupaConstants constants,
final PlaceController pc, final HupaRequestFactory rf) {
super(PAGE_SIZE, Resources.INSTANCE);
this.pc = pc;
this.rf = rf;
this.imageBundle = imageBundle;
CheckboxCell headerCheckbox = new CheckboxCell();
ImageResourceCell headerAttached = new ImageResourceCell();
Header<Boolean> header = new Header<Boolean>(headerCheckbox) {
@Override
public Boolean getValue() {
return false;
}
};
Header<ImageResource> attachedPin = new Header<ImageResource>(headerAttached) {
@Override
public ImageResource getValue() {
return imageBundle.attachmentIcon();
}
};
header.setUpdater(new ValueUpdater<Boolean>() {
@Override
public void update(Boolean value) {
List<Message> displayedItems = MessagesCellTable.this.getVisibleItems();
for (Message msg : displayedItems) {
checkboxCol.getFieldUpdater().update(0, msg, value);
}
}
});
fromCol = getFromColumn();
subjectCol = getSubjectColumn();
attachedCol = getAttachmentColumn();
dateCol = getDateColumn();
addColumn(checkboxCol, new CheckboxHeader(selectionModel, dataProvider));
setColumnWidth(checkboxCol, 3, Unit.EM);
addColumn(fromCol, constants.mailTableFrom());
setColumnWidth(fromCol, 40, Unit.PCT);
addColumn(subjectCol, constants.mailTableSubject());
setColumnWidth(subjectCol, 60, Unit.PCT);
addColumn(attachedCol, attachedPin);
setColumnWidth(attachedCol, 33, Unit.PX);
addColumn(dateCol, constants.mailTableDate());
setColumnWidth(dateCol, 10, Unit.EM);
setRowCount(PAGE_SIZE, false);
this.setStyleBaseOnTag();
// redraw();
setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
setAutoHeaderRefreshDisabled(true);
setSelectionModel(selectionModel, DefaultSelectionEventManager.<Message> createBlacklistManager(0));
// make table sortable
AsyncHandler columnSortHandler = new AsyncHandler(this);
addColumnSortHandler(columnSortHandler);
fromCol.setSortable(true);
subjectCol.setSortable(true);
attachedCol.setSortable(true);
dateCol.setSortable(true);
}
// TODO: this should be perform in the server side, but in the meanwhile it
// is useful
// some kind of sorting in client side.
@Override
public void setVisibleRangeAndClearData(Range range, boolean forceRangeChangeEvent) {
final ColumnSortInfo sortInfo = getColumnSortList().get(0);
List<Message> sortedList = new ArrayList<Message>(getVisibleItems());
Collections.sort(sortedList, new Comparator<Message>() {
public int compare(Message o1, Message o2) {
Column<?, ?> column = sortInfo.getColumn();
Message a = sortInfo.isAscending() ? o1 : o2;
Message b = sortInfo.isAscending() ? o2 : o1;
if (fromCol.equals(column)) {
return a.getFrom().compareToIgnoreCase(b.getFrom());
}
if (attachedCol.equals(column)) {
return Boolean.valueOf(a.hasAttachment()).compareTo(Boolean.valueOf(b.hasAttachment()));
}
if (dateCol.equals(column)) {
return a.getReceivedDate().compareTo(b.getReceivedDate());
}
if (subjectCol.equals(column)) {
// Remove Re & Fwd, using ugly regex since replaceAll is not
// case-insensitive in client side.
String s1 = a.getSubject().replaceAll("^([Rr][Ee]|[Ff][Ww][Dd]): (.+)$", "$2 ");
String s2 = b.getSubject().replaceAll("^([Rr][Ee]|[Ff][Ww][Dd]): (.+)$", "$2 ");
return s1.compareTo(s2);
}
return 0;
}
});
dataProvider.updateRowData(range.getStart(), sortedList);
}
public String parseFolderName(final PlaceController pc) {
Place place = pc.getWhere();
if (place instanceof FolderPlace) {
folderName = ((FolderPlace) place).getToken();
} else if (place instanceof MessagePlace) {
folderName = ((MessagePlace) place).getTokenWrapper().getFolder();
}
return folderName;
}
Message message; // the object selected by selectionModel
public String getMessageStyle(Message row) {
return haveRead(row) ? getReadStyle() : getUnreadStyle();
}
private String getUnreadStyle() {
return Resources.INSTANCE.dataGridStyle().fontBold();
}
private String getReadStyle() {
return Resources.INSTANCE.dataGridStyle().fontNormal();
}
private boolean haveRead(Message row) {
return row.getFlags().contains(IMAPFlag.SEEN);
}
public void markRead(final Message message, final boolean read) {
flush();
}
public class CheckboxColumn extends Column<Message, Boolean> {
public CheckboxColumn() {
super(new CheckboxCell(false, false));
setFieldUpdater(new FieldUpdater<Message, Boolean>() {
@Override
public void update(int index, Message object, Boolean value) {
selectionModel.setSelected(object, value);
int size = selectionModel.getSelectedSet().size();
if (size >= 1) {
toolBar.enableDealingTools(true);
toolBar.enableSendingTools(false);
toolBar.enableUpdatingTools(false);
} else {
toolBar.enableAllTools(false);
}
}
});
}
@Override
public Boolean getValue(Message object) {
return selectionModel.isSelected(object);
}
}
protected Column<Message, SafeHtml> getFromColumn () {
return new Column<Message, SafeHtml>(new SafeHtmlCell()) {
@Override
public SafeHtml getValue(Message object) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
sb.append(SafeHtmlUtils.fromString(object.getFrom() == null ? "" : object.getFrom()));
return sb.toSafeHtml();
}
};
}
protected Column<Message, SafeHtml> getSubjectColumn () {
return new Column<Message, SafeHtml>(new SafeHtmlCell()) {
@Override
public SafeHtml getValue(Message object) {
SafeHtmlBuilder sb = new SafeHtmlBuilder();
sb.append(SafeHtmlUtils.fromString(object.getSubject() == null ? "" : object.getSubject()));
return sb.toSafeHtml();
}
};
}
protected Column<Message, ImageResource> getAttachmentColumn () {
return new Column<Message, ImageResource>(new ImageResourceCell()) {
public ImageResource getValue(Message object) {
return object.hasAttachment() ? imageBundle.attachmentIcon() : null;
}
};
}
protected Column<Message, Date> getDateColumn() {
return new Column<Message, Date>(new DateCell(DateTimeFormat.getFormat("dd.MMM.yyyy"))) {
public Date getValue(Message object) {
return object.getReceivedDate();
}
};
}
public void setStyleBaseOnTag() {
setRowStyles(new RowStyles<Message>() {
@Override
public String getStyleNames(Message row, int rowIndex) {
return getMessageStyle(row);
}
});
}
public void refresh() {
dataProvider.refresh();
redrawHeaders();
}
}