001/* 002 * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl-2.1.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Martin Pernollet 016 */ 017 018package org.nuxeo.ecm.platform.groups.audit.service.acl; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.List; 023import java.util.Set; 024 025import org.apache.poi.ss.usermodel.Cell; 026import org.apache.poi.ss.usermodel.CellStyle; 027import org.nuxeo.ecm.platform.groups.audit.service.acl.ReportLayoutSettings.SpanMode; 028import org.nuxeo.ecm.platform.groups.audit.service.acl.excel.ByteColor; 029import org.nuxeo.ecm.platform.groups.audit.service.acl.excel.ExcelBuilder; 030import org.nuxeo.ecm.platform.groups.audit.service.acl.filter.IContentFilter; 031 032import com.google.common.collect.Multimap; 033 034/** 035 * An excel layout builder that uses one group of columns per user, using one column for each right type (read, write, 036 * etc). 037 * 038 * @author Martin Pernollet <mpernollet@nuxeo.com> 039 */ 040public class AclExcelLayoutBuilderMultiColumn extends AclExcelLayoutBuilder { 041 protected static int USERS_ROW = 0; 042 043 protected static int PERMISSIONS_ROW = 1; 044 045 public static ReportLayoutSettings defaultLayout() { 046 ReportLayoutSettings layout = new ReportLayoutSettings(); 047 layout.userHeaderHeight = -1; 048 layout.userHeaderRotation = 0; 049 layout.aclHeaderHeight = -1;// fit vertically full ACL name 1800; 050 layout.aclHeaderRotation = 0; 051 052 layout.fileTreeColumnWidth = 2.5; // in number of char 053 layout.aclColumnWidth = 2.5; 054 layout.defaultRowHeight = 100; 055 layout.splitPaneX = 500; 056 layout.splitPaneY = 1500; 057 layout.freezePaneRowSplit = 2; 058 layout.treeLineCursorRowStart = 2; 059 060 layout.aclHeaderCommentColSpan = 10; 061 layout.aclHeaderCommentRowSpan = 2; 062 layout.aclHeaderFontSize = 6; // in font unit 063 064 layout.spanMode = SpanMode.COLUMN_OVERFLOW_ON_NEXT_SHEETS; 065 066 layout.zoomRatioDenominator = 2; 067 layout.zoomRatioNumerator = 1; 068 069 layout.logoImageFile = "src/main/resources/file-delete.png"; 070 071 return layout; 072 } 073 074 /* Prebuilt styles */ 075 076 protected CellStyle acceptStyle; 077 078 protected CellStyle acceptStyleLeft; 079 080 protected CellStyle acceptStyleRight; 081 082 protected CellStyle denyStyle; 083 084 protected CellStyle denyStyleLeft; 085 086 protected CellStyle denyStyleRight; 087 088 protected CellStyle emptyStyle; 089 090 protected CellStyle emptyStyleLeft; 091 092 protected CellStyle emptyStyleRight; 093 094 protected int logoPictureId = -1; 095 096 public AclExcelLayoutBuilderMultiColumn() { 097 super(defaultLayout()); 098 } 099 100 public AclExcelLayoutBuilderMultiColumn(IContentFilter filter) { 101 this(defaultLayout(), filter); 102 } 103 104 public AclExcelLayoutBuilderMultiColumn(ReportLayoutSettings layout, IContentFilter filter) { 105 super(layout, filter); 106 } 107 108 @Override 109 protected void renderInit() { 110 super.renderInit(); 111 acceptStyle = excel.newColoredCellStyle(ByteColor.GREEN); 112 113 acceptStyleLeft = excel.newColoredCellStyle(ByteColor.GREEN); 114 acceptStyleLeft.setBorderLeft(CellStyle.BORDER_THIN); 115 acceptStyleLeft.setLeftBorderColor(excel.getColor(ByteColor.BLACK).getIndex()); 116 117 acceptStyleRight = excel.newColoredCellStyle(ByteColor.GREEN); 118 acceptStyleRight.setBorderRight(CellStyle.BORDER_THIN); 119 acceptStyleRight.setRightBorderColor(excel.getColor(ByteColor.BLACK).getIndex()); 120 121 denyStyle = excel.newColoredCellStyle(ByteColor.RED); 122 denyStyle.setFillPattern(CellStyle.THIN_FORWARD_DIAG); // TODO: 123 // generaliser 124 // autres 125 // cellules 126 denyStyle.setFillBackgroundColor(excel.getColor(ByteColor.WHITE).getIndex()); 127 128 denyStyleLeft = excel.newColoredCellStyle(ByteColor.RED); 129 denyStyleLeft.setBorderLeft(CellStyle.BORDER_THIN); 130 denyStyleLeft.setLeftBorderColor(excel.getColor(ByteColor.BLACK).getIndex()); 131 132 denyStyleRight = excel.newColoredCellStyle(ByteColor.RED); 133 denyStyleRight.setBorderRight(CellStyle.BORDER_THIN); 134 denyStyleRight.setRightBorderColor(excel.getColor(ByteColor.BLACK).getIndex()); 135 136 emptyStyle = excel.newColoredCellStyle(ByteColor.WHITE); 137 138 emptyStyleLeft = excel.newColoredCellStyle(ByteColor.WHITE); 139 emptyStyleLeft.setBorderLeft(CellStyle.BORDER_THIN); 140 emptyStyleLeft.setLeftBorderColor(excel.getColor(ByteColor.BLACK).getIndex()); 141 142 emptyStyleRight = excel.newColoredCellStyle(ByteColor.WHITE); 143 emptyStyleRight.setBorderRight(CellStyle.BORDER_THIN); 144 emptyStyleRight.setRightBorderColor(excel.getColor(ByteColor.BLACK).getIndex()); 145 146 if (layoutSettings.logoImageFile != null) 147 try { 148 logoPictureId = excel.loadPicture(layoutSettings.logoImageFile); 149 } catch (IOException e) { 150 log.error(e, e); 151 } 152 } 153 154 /* HEADER RENDERING */ 155 156 /** 157 * Write users and groups on the first row. Memorize the user (or group) column which can later be retrieved with 158 * getColumn(user) 159 */ 160 @Override 161 protected void renderHeader(int tableStartColumn, Set<String> userOrGroups, Set<String> permissions) { 162 renderHeaderPicture(); 163 renderHeaderUsers(tableStartColumn, userOrGroups, permissions); 164 renderHeaderAcl(userOrGroups, permissions); 165 formatHeaderRowHeight(); 166 } 167 168 protected void renderHeaderPicture() { 169 // excel.mergeRange(USERS_ROW, 0, PERMISSIONS_ROW, tableStartColumn-1); 170 excel.setPicture(logoPictureId, 0, 0, false); 171 } 172 173 protected void renderHeaderUsers(int tableStartColumn, Set<String> userOrGroups, Set<String> permissions) { 174 175 int userColumn = tableStartColumn; 176 for (String user : userOrGroups) { 177 // render the user column header 178 excel.setCell(USERS_ROW, userColumn, user, userHeaderStyle); 179 layout.setUserColumn(userColumn, user); 180 181 // merge cells indicating user name 182 final int from = userColumn; 183 final int to = userColumn + permissions.size() - 1; 184 if (from < ExcelBuilder.LAST_COLUMN && to < ExcelBuilder.LAST_COLUMN) 185 excel.mergeRange(USERS_ROW, from, USERS_ROW, to); 186 187 userColumn += permissions.size(); 188 log.debug("user header: " + USERS_ROW + "," + userColumn + " > " + user); 189 } 190 } 191 192 protected void renderHeaderAcl(Set<String> userOrGroups, Set<String> permissions) { 193 for (String user : userOrGroups) { 194 // render ACL column header for this user 195 int userColumn; 196 int aclColumn = 0; 197 int aclHeaderColumn = 0; 198 String aclHeaderText; 199 String aclHeaderShort; 200 201 for (String permission : permissions) { 202 userColumn = layout.getUserColumn(user); 203 aclHeaderColumn = userColumn + aclColumn; 204 aclHeaderText = permission;// formatPermission(permission); 205 aclHeaderShort = formatPermission(permission); 206 207 Cell cell = excel.setCell(PERMISSIONS_ROW, aclHeaderColumn, aclHeaderShort, aclHeaderStyle); 208 excel.setColumnWidth(aclHeaderColumn, (int) (layoutSettings.aclColumnWidth * CELL_WIDTH_UNIT)); 209 210 // add a comment with the acl complete name 211 if ((aclHeaderColumn + layoutSettings.aclHeaderCommentColSpan) < ExcelBuilder.LAST_COLUMN) 212 excel.addComment(cell, aclHeaderText, PERMISSIONS_ROW, aclHeaderColumn, 213 layoutSettings.aclHeaderCommentColSpan, layoutSettings.aclHeaderCommentRowSpan); 214 215 layout.setUserAclColumn(aclHeaderColumn, Pair.of(user, permission)); 216 aclColumn++; 217 218 log.debug("permission header: " + PERMISSIONS_ROW + "," + aclHeaderColumn + " > " 219 + formatPermission(permission)); 220 } 221 } 222 } 223 224 protected void formatHeaderRowHeight() { 225 if (layoutSettings.aclHeaderHeight != -1) 226 excel.setRowHeight(PERMISSIONS_ROW, layoutSettings.aclHeaderHeight); 227 if (layoutSettings.userHeaderHeight != -1) 228 excel.setRowHeight(USERS_ROW, layoutSettings.userHeaderHeight); 229 } 230 231 /* FILE TREE AND MATRIX CONTENT RENDERING */ 232 233 @Override 234 protected void renderAcl(Multimap<String, Pair<String, Boolean>> userAcls) { 235 for (String user : userAcls.keySet()) { 236 List<Pair<String, Boolean>> acls = new ArrayList<Pair<String, Boolean>>(userAcls.get(user)); 237 int last = acls.size() - 1; 238 239 // TODO: IF ACLS not contain an ACL that should be first or last, 240 // thus showing border, post draw white cells 241 242 for (int i = 0; i < acls.size(); i++) { 243 boolean isFirst = false;// (i == 0); 244 boolean isLast = false;// (i == last); 245 246 Pair<String, Boolean> ace = acls.get(i); 247 String permission = ace.a; 248 boolean accept = ace.b; 249 int aclColumn = layout.getUserAclColumn(Pair.of(user, permission)); 250 String aceText = "";// formatAce(ace) 251 252 if (accept) { 253 // draws an accept cell 254 renderAcceptCell(isFirst, isLast, aclColumn, aceText); 255 } else { 256 // draws a deny cell 257 renderDenyCell(isFirst, isLast, aclColumn, aceText); 258 } 259 } 260 // String info = formatAcl(userAcls.get(user)); 261 } 262 } 263 264 /** 265 * Render a cell with a 'deny' color with left, right or no border according to its position. 266 */ 267 protected void renderDenyCell(boolean isFirst, boolean isLast, int aclColumn, String aceText) { 268 if (isFirst) { 269 excel.setCell(treeLineCursor, aclColumn, aceText, denyStyleLeft); 270 } else if (isLast) { 271 excel.setCell(treeLineCursor, aclColumn, aceText, denyStyleRight); 272 } else { 273 excel.setCell(treeLineCursor, aclColumn, aceText, denyStyle); 274 } 275 } 276 277 /** 278 * Render a cell with a 'accept' color with left, right or no border according to its position. 279 */ 280 protected void renderAcceptCell(boolean isFirst, boolean isLast, int aclColumn, String aceText) { 281 if (isFirst) { 282 excel.setCell(treeLineCursor, aclColumn, aceText, acceptStyleLeft); 283 } else if (isLast) { 284 excel.setCell(treeLineCursor, aclColumn, aceText, acceptStyleRight); 285 } else { 286 excel.setCell(treeLineCursor, aclColumn, aceText, acceptStyle); 287 } 288 } 289}