blob: fd0fcb59aa804ed6790baaf51e4ec5eb81f760f8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Chalmers | University of Gothenburg, rt-labs and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Chalmers | University of Gothenburg and rt-labs - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.capra.ui.office.objects;
import java.awt.Desktop;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.eclipse.capra.ui.office.exceptions.CapraOfficeObjectNotFound;
import org.eclipse.capra.ui.office.preferences.OfficePreferences;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
import com.google.common.io.Files;
/**
* This class extends the CapraOfficeObject and provides an object to describe a
* single MS Excel row.
*
* @author Dusan Kalanj
*
*/
public class CapraExcelRow extends CapraOfficeObject {
/**
* RegEx of characters (tabs, newlines, carriage returns and invisible
* control characters) to be replaced with white-spaces in the Office View.
*/
private static final String LINE_BREAKS_AND_CONTROL_REQ = "[\r\n\t\\p{C}]+";
private static final DataFormatter FORMATTER = new DataFormatter();
/**
* Delimiter between excel cells as displayed in the Office View.
*/
private static final String CELL_DELIMITER = " | ";
/**
* Delimiter between sheetId and rowId as used in the uri.
*/
private static final String ID_DELIMITER = "-";
/**
* A constant that is used if the row index isn't found when opening object
* details.
*/
private static final int NO_ROW_INDEX = -1;
/**
* A constant that is used if the last cell in the row isn't found.
*/
private static final String NO_LAST_CELL_REFERENCE = "-1";
/**
* The ID of the column that is used to extract the identifier of the row
* (if value is "0", then line numbers are used as identifiers).
*/
private String idColumn;
/**
* A constructor that generates a new instance of CapraExcelRow where the
* parent properties are extracted from the provided Excel row and File
* object that contains the row.
*
* @param officeFile
* a File object representing the Office document
* @param row
* an Excel row, extracted from an Excel document
*
*/
public CapraExcelRow(File officeFile, Row row, String idColumn) {
super();
this.idColumn = idColumn;
String rowId = getRowIdFromExcelRow(row);
StringBuilder rowBuilder = new StringBuilder();
rowBuilder.append("ID " + rowId + ": ");
boolean firstCellSet = false;
for (int j = 1; j < row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
String cellValue = FORMATTER.formatCellValue(cell);
if (!cellValue.isEmpty()) {
if (!firstCellSet) {
rowBuilder.append(cellValue);
firstCellSet = true;
} else {
rowBuilder.append(CELL_DELIMITER + cellValue);
}
}
}
if (firstCellSet) {
Pattern p = Pattern.compile(LINE_BREAKS_AND_CONTROL_REQ);
Matcher m = p.matcher(rowBuilder);
String rowContent = (m.replaceAll(" ")).trim();
String rowUriEnd = row.getSheet().getSheetName() + ID_DELIMITER + rowId;
String rowUri = CapraOfficeObject.createUri(officeFile, rowUriEnd);
this.setData(rowContent);
this.setUri(rowUri);
}
}
@Override
public void showOfficeObjectInNativeEnvironment() throws CapraOfficeObjectNotFound {
String fileType = Files.getFileExtension(getFile().getAbsolutePath());
String rowId = getRowIdFromObjectUri();
String sheetName = getSheetName();
Sheet sheet;
try (FileInputStream in = new FileInputStream(getFile())) {
if (fileType.equals(CapraOfficeObject.XLSX)) {
sheet = new XSSFWorkbook(in).getSheet(sheetName);
} else {
sheet = new HSSFWorkbook(in).getSheet(sheetName);
}
} catch (IOException e) {
e.printStackTrace();
return;
}
int rowIndex = NO_ROW_INDEX;
String lastCellReference = NO_LAST_CELL_REFERENCE;
for (int i = 0; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row != null) {
String currRowId = getRowIdFromExcelRow(row);
if (currRowId.equals(rowId)) {
rowIndex = i;
lastCellReference = CellReference.convertNumToColString(row.getLastCellNum()) + (rowIndex + 1);
break;
}
}
}
if (rowIndex == NO_ROW_INDEX || lastCellReference == NO_LAST_CELL_REFERENCE)
throw new CapraOfficeObjectNotFound(getRowIdFromObjectUri());
int firstDisplayedRowIndex = (rowIndex - 2 > 0) ? rowIndex - 2 : 1;
if (fileType.equals(CapraOfficeObject.XLSX)) {
XSSFSheet xssfSheet = XSSFSheet.class.cast(sheet);
int sheetIndex = xssfSheet.getWorkbook().getSheetIndex(xssfSheet);
xssfSheet.getWorkbook().setActiveSheet(sheetIndex);
CTSheetViews ctSheetViews = xssfSheet.getCTWorksheet().getSheetViews();
CTSheetView ctSheetView = ctSheetViews.getSheetViewArray(ctSheetViews.sizeOfSheetViewArray() - 1);
ctSheetView.setTopLeftCell("A" + firstDisplayedRowIndex);
CTSelection ctSelection = ctSheetView.addNewSelection();
ctSelection.setActiveCell("A" + (rowIndex + 1));
ctSelection.setSqref(Arrays.asList("A" + (rowIndex + 1) + ":" + lastCellReference));
} else {
HSSFSheet hssfSheet = HSSFSheet.class.cast(sheet);
hssfSheet.setActive(true);
hssfSheet.showInPane((short) (rowIndex), (short) 0);
HSSFRow row = hssfSheet.getRow(rowIndex);
HSSFCell cell = row.getCell(0);
cell.setAsActiveCell(); // TODO doesn't work - bug (but xls doesn't
// necessarily even have to be supported)
}
try (FileOutputStream out = new FileOutputStream(getFile())) {
sheet.getWorkbook().write(out);
} catch (IOException e) {
e.printStackTrace();
}
// TODO If Excel is already open, then this doesn't trigger. Is there a
// way to refresh the application?
try {
Desktop.getDesktop().open(getFile());
} catch (IOException e) {
e.printStackTrace();
return;
}
}
/**
* Extracts the name of the sheet which the object is associated with.
*
* @return name of the sheet
*/
public String getSheetName() {
String itemId = getId();
int lastIndexOfDelimiter = itemId.lastIndexOf(ID_DELIMITER);
return itemId.substring(0, lastIndexOfDelimiter);
}
private String getRowIdFromObjectUri() {
String itemId = getId();
int lastIndexOfDelimiter = itemId.lastIndexOf(ID_DELIMITER);
return itemId.substring(lastIndexOfDelimiter + 1);
}
private String getRowIdFromExcelRow(Row row) {
String rowId = "";
if (idColumn.equals(OfficePreferences.EXCEL_COLUMN_VALUE_DEFAULT))
rowId = Integer.toString(row.getRowNum() + 1);
else
rowId = FORMATTER.formatCellValue(row.getCell(CellReference.convertColStringToIndex(idColumn)));
return rowId;
}
}