blob: 334a6cc7b60be419e88927295e94d56181103aaa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 Boeing.
* 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:
* Boeing - initial API and implementation
*******************************************************************************/
package org.eclipse.ote.ui.eviewer.view;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osee.framework.logging.OseeLog;
import org.eclipse.osee.framework.plugin.core.util.OseeData;
import org.eclipse.osee.ote.client.msg.IOteMessageService;
import org.eclipse.osee.ote.message.ElementPath;
import org.eclipse.ote.ui.eviewer.Activator;
import org.eclipse.ote.ui.eviewer.jobs.CopyToClipboardJob;
import org.eclipse.ote.ui.eviewer.jobs.CopyToCsvFileJob;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
/**
* @author Ken J. Aguilar
*/
public class ElementContentProvider implements Listener, IStructuredContentProvider, IUpdateListener {
private static final String INTERNAL_FILE_NAME = "element_viewer_column_state.csv";
private final ArrayList<SubscriptionDetails> subscriptions = new ArrayList<SubscriptionDetails>(32);
private TableViewer viewer;
private IOteMessageService service;
private final ArrayList<ElementColumn> elementColumns = new ArrayList<ElementColumn>();
private final int limit;
private ViewRefresher refresher;
private boolean autoReveal = true;
private volatile PrintWriter streamToFileWriter = null;
private HashMap<ElementColumn, Integer> valueMap = new HashMap<ElementColumn, Integer>();
private ElementUpdate last = null;
private ReentrantLock streamWriteLock = new ReentrantLock();
private volatile boolean acceptUpdates = true;
public ElementContentProvider(int limit) {
this.limit = limit;
}
@Override
public Object[] getElements(Object inputElement) {
return refresher.getUpdates();
}
@Override
public void dispose() {
if (refresher != null) {
refresher.clearUpdates();
refresher.stop();
}
disposeAllColumns();
}
public void forceUpdate(){
refresher.forceUpdate();
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
this.viewer = (TableViewer) viewer;
if (newInput != null) {
if (oldInput != null) {
dispose();
}
service = (IOteMessageService) newInput;
indexAndSortColumns();
last = null;
refresher = new ViewRefresher(this.viewer, limit);
refresher.setAutoReveal(autoReveal);
refresher.start();
}
}
public void add(ElementPath path) {
add(path, true);
}
public synchronized void add(ElementPath path, boolean save) {
if (findColumn(path)) {
return;
}
create(path);
if (save) {
updateInternalFile();
}
}
private ElementColumn create(ElementPath path) {
ElementColumn newColumn = new ElementColumn(viewer, elementColumns.size(), path);
SubscriptionDetails details = findDetails(path.getMessageClass());
if (details == null) {
details = new SubscriptionDetails(service.subscribe(path.getMessageClass()), this);
subscriptions.add(details);
}
details.addColumn(newColumn);
elementColumns.add(newColumn);
indexAndSortColumns();
newColumn.addMoveListener(this);
return newColumn;
}
private boolean findColumn(ElementPath path) {
String encodedPath = path.encode();
for (ElementColumn column : elementColumns) {
if (column.getElementPath().encode().equals(encodedPath)) {
return true;
}
}
return false;
}
private synchronized void add(Collection<ElementPath> columns, boolean save) {
HashSet<String> existingColumns = new HashSet<String>();
for (ElementColumn column : elementColumns) {
existingColumns.add(column.getElementPath().encode());
}
for (ElementPath path : columns) {
if (existingColumns.contains(path.encode())) {
continue;
}
create(path);
}
if (save) {
updateInternalFile();
}
}
public SubscriptionDetails findDetails(String messageClassName) {
for (SubscriptionDetails details : subscriptions) {
if (details.getSubscription().getMessageClassName().equals(messageClassName)) {
return details;
}
}
return null;
}
@Override
public synchronized void update(SubscriptionDetails details) {
if(acceptUpdates ){
final ElementUpdate update;
if (last == null) {
update = new ElementUpdate(valueMap, elementColumns);
} else {
update = last.next(valueMap, elementColumns);
}
last = update;
refresher.addUpdate(update);
writeToStream(update);
}
}
private void writeToStream(ElementUpdate update) {
try{
streamWriteLock.lock();
if (streamToFileWriter != null) {
int i;
for (i = 0; i < elementColumns.size() - 1; i++) {
Object o = update.getValue(elementColumns.get(i));
if (o != null) {
streamToFileWriter.append(o.toString());
}
streamToFileWriter.append(',');
}
Object o = update.getValue(elementColumns.get(i));
if (o != null) {
streamToFileWriter.append(o.toString());
}
streamToFileWriter.append('\n');
}
} finally {
streamWriteLock.unlock();
}
}
public void clearAllUpdates() {
refresher.clearUpdates();
last = null;
}
/**
* @return the autoReveal
*/
public boolean isAutoReveal() {
return autoReveal;
}
private void indexAndSortColumns() {
valueMap = new HashMap<ElementColumn, Integer>();
ColumnSorter sorter = new ColumnSorter(viewer.getTable().getColumnOrder());
for (ElementColumn column : elementColumns) {
valueMap.put(column, sorter.orderOf(column.recheckIndex()));
}
determineConflicts();
sorter.sort(elementColumns);
}
void determineConflicts() {
Map<String, Boolean> conflicts = new HashMap<String, Boolean>();
for (ElementColumn column : elementColumns) {
if(conflicts.containsKey(column.getElementText())){
conflicts.put(column.getElementText(), true);
} else {
conflicts.put(column.getElementText(), false);
}
}
for (ElementColumn column : elementColumns) {
if(conflicts.get(column.getElementText())){
column.setDuplicateName(true);
} else {
column.setDuplicateName(false);
}
}
}
/**
* @param autoReveal the autoReveal to set
*/
public void setAutoReveal(boolean autoReveal) {
this.autoReveal = autoReveal;
if (refresher != null) {
refresher.setAutoReveal(autoReveal);
}
}
public synchronized List<ElementColumn> getColumns() {
return new ArrayList<ElementColumn>(elementColumns);
}
public synchronized void putColumnsInList(List<ElementColumn> list) {
list.addAll(elementColumns);
}
public synchronized void removeColumn(ElementColumn column) {
if (elementColumns.remove(column)) {
column.removeMoveListener(this);
SubscriptionDetails subscription = findDetails(column.getMessageClassName());
if (subscription.removeColumn(column)) {
subscription.dispose();
subscriptions.remove(subscription);
}
indexAndSortColumns();
updateInternalFile();
}
}
private void enableMoveListeneing(boolean enable) {
for (ElementColumn column : elementColumns) {
if (enable) {
column.addMoveListener(this);
} else {
column.removeMoveListener(this);
}
}
}
public synchronized void removeColumn(Collection<ElementColumn> columns) {
enableMoveListeneing(false);
elementColumns.removeAll(columns);
viewer.getTable().setRedraw(false);
for (ElementColumn column : columns) {
SubscriptionDetails subscription = findDetails(column.getMessageClassName());
if (subscription.removeColumn(column)) {
subscription.dispose();
subscriptions.remove(subscription);
}
}
enableMoveListeneing(true);
indexAndSortColumns();
viewer.getTable().setRedraw(true);
updateInternalFile();
}
private void updateInternalFile() {
try {
saveColumnsToFile(OseeData.getFile(INTERNAL_FILE_NAME));
} catch (Exception e) {
OseeLog.log(Activator.class, Level.SEVERE, "could not write columns", e);
}
}
public synchronized void saveColumnsToFile(File file) throws FileNotFoundException, IOException {
PrintWriter writer = new PrintWriter(new FileOutputStream(file));
try {
if (elementColumns.isEmpty()) {
return;
}
int i;
for (i = 0; i < elementColumns.size() - 1; i++) {
ElementColumn column = elementColumns.get(i);
writer.write(column.getElementPath().encode());
writer.write('=');
writer.write(column.isActive() ? "active" : "inactive");
writer.write(',');
}
ElementColumn column = elementColumns.get(i);
writer.write(column.getElementPath().encode());
writer.write('=');
writer.write(column.isActive() ? "active" : "inactive");
writer.write('\n');
writer.flush();
} finally {
writer.close();
}
}
private void loadColumns(String[] columnNames) {
LinkedList<ElementPath> columnsToAdd = new LinkedList<ElementPath>();
HashSet<ElementPath> inactiveColumns = new HashSet<ElementPath>();
viewer.getTable().setRedraw(false);
for (String name : columnNames) {
String[] parts = name.split("=");
ElementPath path = ElementPath.decode(parts[0]);
columnsToAdd.add(path);
if (parts.length > 1 && parts[1].equals("inactive")) {
inactiveColumns.add(path);
}
}
add(columnsToAdd, false);
for (ElementColumn column : elementColumns) {
if (inactiveColumns.contains(column.getElementPath())) {
column.setActive(false);
}
}
viewer.getTable().setRedraw(true);
updateInternalFile();
}
public void loadColumnsFromFile(File file) throws FileNotFoundException, IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
try {
String line = reader.readLine();
if (line == null) {
// empty file
return;
}
String[] columnNames = line.split(",");
loadColumns(columnNames);
} finally {
reader.close();
}
}
public synchronized void removeAll() {
disposeAllColumns();
updateInternalFile();
refresher.clearUpdates();
}
private void disposeAllColumns() {
// we must remove all the move listeners first before we dispose or else bad things happen
enableMoveListeneing(false);
for (SubscriptionDetails details : subscriptions) {
details.dispose();
}
subscriptions.clear();
elementColumns.clear();
}
public void toClipboard(Clipboard clipboard) {
CopyToClipboardJob job = new CopyToClipboardJob(clipboard, elementColumns, refresher.getUpdates());
job.schedule();
}
public void toCsv(File file) throws IOException {
CopyToCsvFileJob job = new CopyToCsvFileJob(file, elementColumns, refresher.getUpdates());
job.schedule();
}
public void loadLastColumns() {
try {
File file = OseeData.getFile(INTERNAL_FILE_NAME);
if (file.isFile()) {
loadColumnsFromFile(file);
}
} catch (Exception e) {
OseeLog.log(Activator.class, Level.SEVERE, "could not read columns file", e);
}
}
public void streamToFile(File file) throws FileNotFoundException, IOException {
try{
streamWriteLock.lock();
if (streamToFileWriter != null) {
// stop streaming
streamToFileWriter.flush();
streamToFileWriter.close();
streamToFileWriter = null;
}
if (file == null) {
setMoveableColumns(true);
return;
}
setMoveableColumns(false);
streamToFileWriter = new PrintWriter(new FileOutputStream(file));
int i;
for (i = 0; i < elementColumns.size() - 1; i++) {
streamToFileWriter.write(elementColumns.get(i).getName());
streamToFileWriter.write(',');
}
if (elementColumns.size() > 0) {
streamToFileWriter.write(elementColumns.get(i).getName());
streamToFileWriter.write('\n');
}
streamToFileWriter.flush();
} finally {
streamWriteLock.unlock();
}
}
private void setMoveableColumns(boolean moveable) {
for (ElementColumn column : elementColumns) {
column.getColumn().setMoveable(moveable);
}
}
/**
* handles the reordering of columns
*/
@Override
public void handleEvent(Event event) {
if (event.widget.isDisposed() || event.type != SWT.Move) {
return;
}
synchronized (this) {
indexAndSortColumns();
updateInternalFile();
}
}
public TableViewer getViewer() {
return viewer;
}
public void setUpdateView(boolean updateView) {
refresher.setUpdateView(updateView);
}
public void togglePauseUpdates() {
acceptUpdates = !acceptUpdates;
}
}