//This product is provided under the terms of EPL (Eclipse Public License) //version 1.0. // //The full license text can be read from: http://www.eclipse.org/org/documents/epl-v10.php package org.dtangler.swingui.mainview.impl; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JOptionPane; import org.dtangler.core.analysis.configurableanalyzer.ConfigurableDependencyAnalyzer; import org.dtangler.core.analysisresult.AnalysisResult; import org.dtangler.core.analysisresult.Violation; import org.dtangler.core.configuration.Arguments; import org.dtangler.core.dependencies.Dependable; import org.dtangler.core.dependencies.Dependencies; import org.dtangler.core.dependencies.Dependency; import org.dtangler.core.dependencies.DependencyGraph; import org.dtangler.core.dependencies.Scope; import org.dtangler.core.dependencies.Dependencies.DependencyFilter; import org.dtangler.core.dependencyengine.DependencyEngine; import org.dtangler.core.dependencyengine.DependencyEngineFactory; import org.dtangler.core.dsm.Dsm; import org.dtangler.core.dsmengine.DsmEngine; import org.dtangler.core.exception.DtException; import org.dtangler.swingui.fileinput.FileInputSelection; import org.dtangler.swingui.fileinput.FileInputSelector; import org.dtangler.swingui.rulesselector.RulesSelector; import org.dtangler.ui.dsm.DsmGuiModel; import org.dtangler.ui.dsm.DsmGuiModelChangeListener; import org.dtangler.ui.dsm.DsmGuiModel.DisplayNameFormat; public class DefaultMainViewModel implements MainViewModel { private final DsmGuiModel dsmModel; private final ConfigurationModel configModel; private final FileInputSelector inputSelector; private final DependencyEngineFactory dependencyEngineFactory; private DependencyEngine dependencyEngine; private final RulesSelector rulesSelector; private class ScopeLevelState { private final Set<Dependable> currentParents = new HashSet<Dependable>(); private Dependencies.DependencyFilter dependencyFilter; private List<Integer> selectedRows; private List<Integer> selectedCols; public Set<Dependable> getCurrentParents() { return currentParents; } public void setDependencyFilter( Dependencies.DependencyFilter dependencyFilter) { this.dependencyFilter = dependencyFilter; } public Dependencies.DependencyFilter getDependencyFilter() { return dependencyFilter == null ? DependencyFilter.none : dependencyFilter; } public void setSelectedCells(List<Integer> selectedRows, List<Integer> selectedCols) { this.selectedRows = selectedRows; this.selectedCols = selectedCols; } public List<Integer> getSelectedRows() { return selectedRows == null ? Collections.<Integer> emptyList() : selectedRows; } public List<Integer> getSelectedCols() { return selectedCols == null ? Collections.<Integer> emptyList() : selectedCols; } } private final Map<Scope, ScopeLevelState> scopeLevelStates = new HashMap<Scope, ScopeLevelState>(); private AnalysisResult analysisResult; private Dependencies dependencies; private Scope scope; private DependencyGraph dependencyGraph; public DefaultMainViewModel(DsmGuiModel dsmModel, ConfigurationModel configModel, FileInputSelector inputSelector, RulesSelector rulesSelector, DependencyEngineFactory dependencyEngineFactory) { this.dsmModel = dsmModel; this.configModel = configModel; this.inputSelector = inputSelector; this.rulesSelector = rulesSelector; this.dependencyEngineFactory = dependencyEngineFactory; refresh(); } private void setDependencyEngine(Arguments arguments) { if (dependencyEngineFactory != null) { dependencyEngine = dependencyEngineFactory .getDependencyEngine(arguments); } if (dependencyEngineFactory == null || dependencyEngine == null) throw new DtException( "unable to determine the dependency engine to be used"); } public void refresh() { setDependencyEngine(getArguments()); dependencies = dependencyEngine.getDependencies(getArguments()); clearAllScopeLevelState(); updateScope(); updateAnalysisResult(); updateDependencyGraph(true); } private Arguments getArguments() { return configModel.getArguments(); } private void updateScope() { if (scope == null) { scope = dependencies.getDefaultScope(); } if (!dependencies.getAvailableScopes().contains(scope) && !dependencies.getAvailableScopes().isEmpty()) scope = dependencies.getAvailableScopes().get(0); } private void updateDependencyGraph(boolean updateIfEmpty) { dependencyGraph = getDependencyGraph(); if (!updateIfEmpty && (dependencyGraph == null || dependencyGraph.getAllItems() == null || dependencyGraph .getAllItems().size() == 0)) return; updateDsm(dependencyGraph); } private void updateDsm(DependencyGraph graph) { Dsm dsm = new DsmEngine(graph).createDsm(); dsmModel.setDsm(dsm, analysisResult); } private void updateAnalysisResult() { analysisResult = new ConfigurableDependencyAnalyzer(getArguments()) .analyze(this.dependencies); } private ScopeLevelState getScopeLevelState(Scope scope) { ScopeLevelState scopeLevelState = scopeLevelStates.get(scope); if (scopeLevelState == null) { scopeLevelState = new ScopeLevelState(); scopeLevelStates.put(scope, scopeLevelState); } return scopeLevelState; } private void clearAllScopeLevelState() { scopeLevelStates.clear(); } private void updateDependencyGraph(Scope scope, Set<Dependable> parents, Dependencies.DependencyFilter dependencyFilter, boolean updateIfEmpty) { this.scope = scope; ScopeLevelState scopeLevelState = getScopeLevelState(scope); scopeLevelState.getCurrentParents().clear(); scopeLevelState.getCurrentParents().addAll(parents); scopeLevelState.setDependencyFilter(dependencyFilter); updateDependencyGraph(updateIfEmpty); } private DependencyGraph getDependencyGraph() { Dependencies.DependencyFilter dependencyFilter = getScopeLevelState(scope).dependencyFilter; if (getScopeLevelState(scope).getCurrentParents().isEmpty()) return dependencies.getDependencyGraph(scope); if (getScopeLevelState(scope).getCurrentParents().size() < 2) { dependencyFilter = Dependencies.DependencyFilter.none; getScopeLevelState(scope).setDependencyFilter(dependencyFilter); } DependencyGraph graph = dependencies .getDependencyGraph(scope, getScopeLevelState(scope) .getCurrentParents(), dependencyFilter); return graph; } public void addDsmModelChangeListener(DsmGuiModelChangeListener listener) { dsmModel.addChangeListener(listener); } public List<String> getAllViolations() { if (dependencyGraph == null) return Collections.emptyList(); return sortAndFormatViolations(analysisResult .getViolations(dependencyGraph.getAllItems())); } public List<String> getSelectionViolations() { Set<Violation> violations = new HashSet<Violation>(); for (Dependency dep : dsmModel.getSelectionDependencies()) violations.addAll(analysisResult.getViolations(dep)); for (Dependable dep : dsmModel.getSelectionDependables()) violations.addAll(analysisResult.getChildViolations(Collections .singleton(dep))); return sortAndFormatViolations(violations); } private List<String> sortAndFormatViolations(Set<Violation> violations) { List<String> result = new ArrayList<String>(); for (Violation v : violations) result.add(v.asText()); Collections.sort(result); return result; } public void selectNewInput() { FileInputSelection currentFileInputSelection = new FileInputSelection( dependencyEngine.getDependencyEngineId(), getArguments() .getInput(), getArguments().getIgnoredFileMasks()); FileInputSelection newInputSelection = inputSelector .selectInput(currentFileInputSelection); if (newInputSelection != null) { getArguments().setDependencyEngineId(newInputSelection.getEngine()); getArguments().setInput(newInputSelection.getPaths()); getArguments().setIgnoredFileMasks( newInputSelection.getIgnoredFileMasks()); clearWindowState(); refresh(); } } public void editRules() { Arguments newArguments = rulesSelector.selectRules(getArguments()); if (newArguments == null) return; configModel.setArguments(newArguments); refresh(); } public void addForbiddenDeps() { Map<String, Set<String>> forbiddenDeps = new HashMap<String, Set<String>>( getArguments().getForbiddenDependencies()); Set<Dependency> newForbiddenDeps = dsmModel.getSelectionDependencies(); for (Dependency dep : newForbiddenDeps) addForbiddenDep(forbiddenDeps, dep); getArguments().setForbiddenDependencies(forbiddenDeps); refresh(); } private void addForbiddenDep(Map<String, Set<String>> forbiddenDeps, Dependency dep) { if (dep.getDependant().equals(dep.getDependee())) return; Set<String> newDependees = new HashSet<String>(); newDependees.add(dep.getDependee().getDisplayName()); String dependant = dep.getDependant().getDisplayName(); Set<String> currentDependees = forbiddenDeps.get(dependant); if (currentDependees != null) newDependees.addAll(currentDependees); forbiddenDeps.put(dependant, newDependees); } public boolean cellSelectionExists() { return !dsmModel.getSelectionDependencies().isEmpty(); } public boolean selectionExists() { return !dsmModel.getSelectionDependables().isEmpty(); } public void openConfiguration() { if (!configModel.openConfiguration()) return; clearWindowState(); refresh(); } public void save() { configModel.save(); } public void saveAs() { configModel.saveAs(); } public String getFileName() { return configModel.getFileName(); } public void newConfiguration() { if (!configModel.newConfiguration()) return; clearWindowState(); refresh(); } public boolean isDirty() { return configModel.isDirty(); } public List<? extends Scope> getScopes() { if (dependencies == null) return Collections.emptyList(); return dependencies.getAvailableScopes(); } public Scope getScope() { return scope; } public void setScope(Scope scope) { clearAllScopeLevelState(); updateDependencyGraph(scope, Collections.<Dependable> emptySet(), Dependencies.DependencyFilter.none, true); } private boolean isDataCellSelected() { if (!isValidCellSelection(dsmModel.getSelectedRows(), dsmModel .getSelectedCols())) { return false; } for (Integer col : dsmModel.getSelectedCols()) { if (col != null && col >= 0) return true; } return false; } public void zoomIn() { if (!deeperLevelExists()) return; Dependencies.DependencyFilter dependencyFilter = Dependencies.DependencyFilter.none; if (isDataCellSelected()) dependencyFilter = Dependencies.DependencyFilter.itemsContributingToTheParentDependencyWeight; zoomIn(dependencyFilter); } public void zoomIn(Dependencies.DependencyFilter dependencyFilter) { if (!deeperLevelExists()) return; saveCurrentCellSelectionToWindowState(); updateDependencyGraph(dependencies.getChildScope(scope), dsmModel .getSelectionDependables(), dependencyFilter, false); if (dependencyGraph == null || dependencyGraph.getAllItems() == null || dependencyGraph.getAllItems().size() == 0) { String errorMessage = "No contents found at the scope level " + scope + "."; if (getScopeLevelState(scope).getDependencyFilter() == DependencyFilter.itemsContributingToTheParentDependencyWeight) { errorMessage = "No dependencies between the selected items at the scope level " + scope + "."; } JOptionPane.showMessageDialog(null, errorMessage, "DSM", JOptionPane.INFORMATION_MESSAGE); zoomOut(); } } private boolean isValidCellSelection(List<Integer> selectedRows, List<Integer> selectedCols) { int selectedRowCount = selectedRows.size(); int selectedColCount = selectedCols.size(); if (selectedRowCount > 0 || selectedColCount > 0) { Integer rowCount = dsmModel.getRowCount(); Integer colCount = dsmModel.getColumnCount(); for (Integer row : selectedRows) { if (row != null && row < rowCount) { continue; } return false; } for (Integer col : selectedCols) { if (col != null && col < colCount) { continue; } return false; } return true; } return false; } private void saveCurrentCellSelectionToWindowState() { ScopeLevelState scopeLevelState = getScopeLevelState(this.scope); scopeLevelState.setSelectedCells(dsmModel.getSelectedRows(), dsmModel .getSelectedCols()); } private void restoreCellSelectionFromWindowState() { ScopeLevelState scopeLevelState = getScopeLevelState(this.scope); if (isValidCellSelection(scopeLevelState.getSelectedRows(), scopeLevelState.getSelectedCols())) { dsmModel.selectCells(scopeLevelState.getSelectedRows(), scopeLevelState.getSelectedCols()); // TODO set the popup menu here } } public void zoomOut() { Scope parentScope = dependencies.getParentScope(scope); this.scope = parentScope; updateDependencyGraph(true); restoreCellSelectionFromWindowState(); } public boolean deeperLevelExists() { return scope != null && dependencies.getChildScope(scope) != null; } public boolean higherLevelExists() { return scope != null && dependencies.getParentScope(scope) != null; } public boolean canExit() { return configModel.canLooseCurrentConfiguration(); } public boolean isShortNameEnabled() { return dsmModel.getDisplayNameFormat().equals( DisplayNameFormat.shortened); } public void toggleShortName() { dsmModel .setDisplayNameFormat(isShortNameEnabled() ? DisplayNameFormat.full : DisplayNameFormat.shortened); } public void addLocations(List<File> files) { List<String> input = new ArrayList<String>(getArguments().getInput()); for (File file : files) { if (!input.contains(file.getAbsolutePath())) input.add(file.getAbsolutePath()); } getArguments().setInput(input); refresh(); } private void clearWindowState() { scope = null; clearAllScopeLevelState(); } public void openConfiguration(File file) { configModel.openConfiguration(file.getAbsolutePath()); clearWindowState(); refresh(); } }