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