| /******************************************************************************* |
| * 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; |
| } |
| } |