///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General // Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.web.address; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.wicket.AttributeModifier; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.SubmitLink; import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.RepeatingView; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.spring.injection.annot.SpringBean; import org.projectforge.address.AddressDO; import org.projectforge.address.AddressDao; import org.projectforge.address.AddressExport; import org.projectforge.address.PersonalAddressDO; import org.projectforge.address.PersonalAddressDao; import org.projectforge.address.PhoneType; import org.projectforge.common.DateHelper; import org.projectforge.core.ConfigXml; import org.projectforge.web.WebConfiguration; import org.projectforge.web.calendar.DateTimeFormatter; import org.projectforge.web.wicket.AbstractEditPage; import org.projectforge.web.wicket.AbstractListPage; import org.projectforge.web.wicket.CellItemListener; import org.projectforge.web.wicket.CellItemListenerPropertyColumn; import org.projectforge.web.wicket.DownloadUtils; import org.projectforge.web.wicket.IListPageColumnsCreator; import org.projectforge.web.wicket.ListPage; import org.projectforge.web.wicket.ListSelectActionPanel; import org.projectforge.web.wicket.RowCssClass; import org.projectforge.web.wicket.components.ContentMenuEntryPanel; import org.projectforge.web.wicket.components.ExternalLinkPanel; import org.projectforge.web.wicket.flowlayout.IconLinkPanel; import org.projectforge.web.wicket.flowlayout.IconType; @ListPage(editPage = AddressEditPage.class) public class AddressListPage extends AbstractListPage<AddressListForm, AddressDao, AddressDO> implements IListPageColumnsCreator<AddressDO> { private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(AddressListPage.class); private static final long serialVersionUID = 5168079498385464639L; private static final String APPLE_SCRIPT_DIR = "misc/"; private static final String APPLE_SCRIPT_FOR_ADDRESS_BOOK = "AddressBookRemoveNotesOfClassWork.scpt"; protected static final String[] MY_BOOKMARKABLE_INITIAL_PROPERTIES = mergeStringArrays(BOOKMARKABLE_INITIAL_PROPERTIES, new String[] { "f.listType|lt", "f.uptodate", "f.outdated", "f.leaved", "f.active", "f.nonActive", "f.uninteresting", "f.personaIngrata", "f.departed"}); @SpringBean(name = "addressDao") private AddressDao addressDao; @SpringBean(name = "addressExport") private AddressExport addressExport; @SpringBean(name = "personalAddressDao") private PersonalAddressDao personalAddressDao; Map<Integer, PersonalAddressDO> personalAddressMap; boolean messagingSupported; boolean phoneCallSupported; public AddressListPage(final PageParameters parameters) { super(parameters, "address"); } @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); response.render(JavaScriptReferenceHeaderItem.forUrl("scripts/zoom.js")); } @Override protected void setup() { super.setup(); this.recentSearchTermsUserPrefKey = "addressSearchTerms"; messagingSupported = ConfigXml.getInstance().isSmsConfigured() == true; phoneCallSupported = ConfigXml.getInstance().isTelephoneSystemUrlConfigured() == true; } @Override @SuppressWarnings("serial") public List<IColumn<AddressDO, String>> createColumns(final WebPage returnToPage, final boolean sortable) { final List<IColumn<AddressDO, String>> columns = new ArrayList<IColumn<AddressDO, String>>(); final CellItemListener<AddressDO> cellItemListener = new CellItemListener<AddressDO>() { @Override public void populateItem(final Item<ICellPopulator<AddressDO>> item, final String componentId, final IModel<AddressDO> rowModel) { final AddressDO address = rowModel.getObject(); final PersonalAddressDO personalAddress = personalAddressMap.get(address.getId()); appendCssClasses(item, address.getId(), address.isDeleted()); if (address.isDeleted() == true) { // Do nothing further } else if (personalAddress != null && personalAddress.isFavoriteCard() == true) { appendCssClasses(item, RowCssClass.FAVORITE_ENTRY); } } }; columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("modified")), getSortable("lastUpdate", sortable), "lastUpdate", cellItemListener) { /** * @see org.projectforge.web.wicket.CellItemListenerPropertyColumn#populateItem(org.apache.wicket.markup.repeater.Item, * java.lang.String, org.apache.wicket.model.IModel) */ @Override public void populateItem(final Item<ICellPopulator<AddressDO>> item, final String componentId, final IModel<AddressDO> rowModel) { final AddressDO address = rowModel.getObject(); final RepeatingView view = new RepeatingView(componentId); item.add(view); view.add(new ListSelectActionPanel(view.newChildId(), rowModel, AddressEditPage.class, address.getId(), returnToPage, DateTimeFormatter.instance().getFormattedDate(address.getLastUpdate()))); view.add(new IconLinkPanel(view.newChildId(), IconType.PRINT, new ResourceModel("printView"), new Link<Void>(IconLinkPanel.LINK_ID) { @Override public void onClick() { final PageParameters params = new PageParameters(); params.add(AbstractEditPage.PARAMETER_KEY_ID, address.getId()); final AddressViewPage addressViewPage = new AddressViewPage(params); setResponsePage(addressViewPage); } })); addRowClick(item); cellItemListener.populateItem(item, componentId, rowModel); } }); columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("name")), getSortable("name", sortable), "name", cellItemListener)); columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("firstName")), getSortable("firstName", sortable), "firstName", cellItemListener)); columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("organization")), getSortable("organization", sortable), "organization", cellItemListener)); columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("email")), null, "email", cellItemListener) { /** * @see org.projectforge.web.wicket.CellItemListenerPropertyColumn#populateItem(org.apache.wicket.markup.repeater.Item, * java.lang.String, org.apache.wicket.model.IModel) */ @Override public void populateItem(final Item<ICellPopulator<AddressDO>> item, final String componentId, final IModel<AddressDO> rowModel) { final AddressDO address = rowModel.getObject(); final RepeatingView view = new RepeatingView(componentId); item.add(view); boolean first = true; if (StringUtils.isNotBlank(address.getEmail()) == true) { final ExternalLinkPanel mailToLinkPanel = new ExternalLinkPanel(view.newChildId(), "mailto:" + address.getEmail(), address .getEmail()); mailToLinkPanel.getLink().add(AttributeModifier.replace("onclick", "javascript:suppressNextRowClick();")); view.add(mailToLinkPanel); first = false; } if (StringUtils.isNotBlank(address.getPrivateEmail()) == true) { if (first == true) { first = false; } else { view.add(new Label(view.newChildId(), "<br/>").setEscapeModelStrings(false)); } view.add(new ExternalLinkPanel(view.newChildId(), "mailto:" + address.getPrivateEmail(), address.getPrivateEmail())); } cellItemListener.populateItem(item, componentId, rowModel); } }); columns.add(new CellItemListenerPropertyColumn<AddressDO>(new Model<String>(getString("address.phoneNumbers")), null, null, cellItemListener) { /** * @see org.projectforge.web.wicket.CellItemListenerPropertyColumn#populateItem(org.apache.wicket.markup.repeater.Item, * java.lang.String, org.apache.wicket.model.IModel) */ @Override public void populateItem(final Item<ICellPopulator<AddressDO>> item, final String componentId, final IModel<AddressDO> rowModel) { final AddressDO address = rowModel.getObject(); final PersonalAddressDO personalAddress = personalAddressMap.get(address.getId()); final RepeatingView view = new RepeatingView(componentId); item.add(view); final Integer id = address.getId(); boolean first = addPhoneNumber(view, id, PhoneType.BUSINESS, address.getBusinessPhone(), (personalAddress != null && personalAddress.isFavoriteBusinessPhone() == true), false, IconType.BUILDING, true); first = addPhoneNumber(view, id, PhoneType.MOBILE, address.getMobilePhone(), (personalAddress != null && personalAddress.isFavoriteMobilePhone() == true), true, IconType.TABLET, first); first = addPhoneNumber(view, id, PhoneType.PRIVATE, address.getPrivatePhone(), (personalAddress != null && personalAddress.isFavoritePrivatePhone() == true), false, IconType.HOME, first); first = addPhoneNumber(view, id, PhoneType.PRIVATE_MOBILE, address.getPrivateMobilePhone(), (personalAddress != null && personalAddress.isFavoritePrivateMobilePhone() == true), true, IconType.TABLET, first); cellItemListener.populateItem(item, componentId, rowModel); item.add(AttributeModifier.append("style", new Model<String>("white-space: nowrap;"))); } }); return columns; } @SuppressWarnings("serial") @Override protected void init() { personalAddressMap = personalAddressDao.getPersonalAddressByAddressId(); final List<IColumn<AddressDO, String>> columns = createColumns(this, true); dataTable = createDataTable(columns, "name", SortOrder.ASCENDING); form.add(dataTable); if (messagingSupported == true) { final ContentMenuEntryPanel menuEntry = new ContentMenuEntryPanel(getNewContentMenuChildId(), new Link<Object>("link") { @Override public void onClick() { setResponsePage(SendSmsPage.class, new PageParameters()); }; }, getString("address.tooltip.writeSMS")); addContentMenuEntry(menuEntry); } if (WebConfiguration.isDevelopmentMode() == true) { // final Import vcards final BookmarkablePageLink<AddressImportPage> importVCardsLink = new BookmarkablePageLink<AddressImportPage>( ContentMenuEntryPanel.LINK_ID, AddressImportPage.class); final ContentMenuEntryPanel importVCardsButton = new ContentMenuEntryPanel(getNewContentMenuChildId(), importVCardsLink, getString("address.book.vCardImport")).setTooltip(getString("address.book.vCardImport.tooltip")); addContentMenuEntry(importVCardsButton); } final ContentMenuEntryPanel exportMenu = new ContentMenuEntryPanel(getNewContentMenuChildId(), getString("export")); addContentMenuEntry(exportMenu); { // Export vcards final SubmitLink exportVCardsLink = new SubmitLink(ContentMenuEntryPanel.LINK_ID, form) { @Override public void onSubmit() { log.info("Exporting personal address book."); final List<PersonalAddressDO> list = addressDao.getFavoriteVCards(); if (CollectionUtils.isEmpty(list) == true) { form.addError("address.book.hasNoVCards"); return; } final String filename = "ProjectForge-PersonalAddressBook_" + DateHelper.getDateAsFilenameSuffix(new Date()) + ".vcf"; final StringWriter writer = new StringWriter(); addressDao.exportFavoriteVCards(writer, list); DownloadUtils.setUTF8CharacterEncoding(getResponse()); DownloadUtils.setDownloadTarget(writer.toString().getBytes(), filename); } }; final ContentMenuEntryPanel exportVCardsButton = new ContentMenuEntryPanel(exportMenu.newSubMenuChildId(), exportVCardsLink, getString("address.book.vCardExport")).setTooltip(getString("address.book.vCardExport.tooltip.title"), getString("address.book.vCardExport.tooltip.content")); exportMenu.addSubMenuEntry(exportVCardsButton); } { // Excel export final SubmitLink excelExportLink = new SubmitLink(ContentMenuEntryPanel.LINK_ID, form) { @Override public void onSubmit() { log.info("Exporting address list."); final List<AddressDO> list = getList(); final byte[] xls = addressExport.export(list, personalAddressMap); if (xls == null || xls.length == 0) { form.addError("address.book.hasNoVCards"); return; } final String filename = "ProjectForge-AddressExport_" + DateHelper.getDateAsFilenameSuffix(new Date()) + ".xls"; DownloadUtils.setDownloadTarget(xls, filename); } }; final ContentMenuEntryPanel excelExportButton = new ContentMenuEntryPanel(exportMenu.newSubMenuChildId(), excelExportLink, getString("address.book.export")).setTooltip(getString("address.book.export"), getString("address.book.export.tooltip")); exportMenu.addSubMenuEntry(excelExportButton); } { // Phone list export final SubmitLink exportPhoneListLink = new SubmitLink(ContentMenuEntryPanel.LINK_ID, form) { @Override public void onSubmit() { log.info("Exporting phone list"); final List<PersonalAddressDO> list = addressDao.getFavoritePhoneEntries(); if (CollectionUtils.isEmpty(list) == true) { form.addError("address.book.hasNoPhoneNumbers"); return; } final String filename = "ProjectForge-PersonalPhoneList_" + DateHelper.getDateAsFilenameSuffix(new Date()) + ".txt"; final StringWriter writer = new StringWriter(); addressDao.exportFavoritePhoneList(writer, list); DownloadUtils.setUTF8CharacterEncoding(getResponse()); DownloadUtils.setDownloadTarget(writer.toString().getBytes(), filename); } }; final ContentMenuEntryPanel exportPhoneListButton = new ContentMenuEntryPanel(exportMenu.newSubMenuChildId(), exportPhoneListLink, getString("address.book.exportFavoritePhoneList")).setTooltip(getString("address.book.exportFavoritePhoneList.tooltip.title"), getString("address.book.exportFavoritePhoneList.tooltip.content")); exportMenu.addSubMenuEntry(exportPhoneListButton); } { final ContentMenuEntryPanel extendedMenu = contentMenuBarPanel.ensureAndAddExtendetMenuEntry(); // Apple script export final SubmitLink appleScriptLink = new SubmitLink(ContentMenuEntryPanel.LINK_ID, form) { @Override public void onSubmit() { byte[] content = null; final String file = APPLE_SCRIPT_DIR + APPLE_SCRIPT_FOR_ADDRESS_BOOK; try { final ClassLoader cLoader = this.getClass().getClassLoader(); final InputStream is = cLoader.getResourceAsStream(file); if (is == null) { log.error("Could not find script in resource path: '" + file + "'."); } content = IOUtils.toByteArray(is); } catch (final IOException ex) { log.error("Could not load script '" + file + "'." + ex.getMessage(), ex); throw new RuntimeException(ex); } DownloadUtils.setDownloadTarget(content, APPLE_SCRIPT_FOR_ADDRESS_BOOK); } }; final ContentMenuEntryPanel appleScriptButton = new ContentMenuEntryPanel(extendedMenu.newSubMenuChildId(), appleScriptLink, getString("address.book.export.appleScript4Notes")).setTooltip(getString("address.book.export.appleScript4Notes"), getString("address.book.export.appleScript4Notes.tooltip")); extendedMenu.addSubMenuEntry(appleScriptButton); } } private boolean addPhoneNumber(final RepeatingView view, final Integer addressId, final PhoneType phoneType, final String phoneNumber, final boolean favoriteNumber, final boolean sendSms, final IconType icon, final boolean first) { if (StringUtils.isBlank(phoneNumber) == true) { return first; } if (first == false) { view.add(new Label(view.newChildId(), "<br/>").setEscapeModelStrings(false).setRenderBodyOnly(true)); } final AddressListPhoneNumberPanel phoneNumberPanel = new AddressListPhoneNumberPanel(view.newChildId(), this, addressId, phoneType, phoneNumber, favoriteNumber, sendSms, icon, first); view.add(phoneNumberPanel); return false; } /** * @see org.projectforge.web.wicket.AbstractListPage#getBookmarkableInitialProperties() */ @Override protected String[] getBookmarkableInitialProperties() { return MY_BOOKMARKABLE_INITIAL_PROPERTIES; } @Override public void refresh() { super.refresh(); if (form.getSearchFilter().isNewest() == true && StringUtils.isBlank(form.getSearchFilter().getSearchString()) == true) { form.getSearchFilter().setMaxRows(form.getPageSize()); } } @Override protected AddressListForm newListForm(final AbstractListPage< ? , ? , ? > parentPage) { return new AddressListForm(this); } @Override protected AddressDao getBaseDao() { return addressDao; } protected AddressDao getAddressDao() { return addressDao; } }