Commit 46c5e516 authored by Dongyue Mou's avatar Dongyue Mou
Browse files

implemented page number support in requirement editor

refs 1407
parent 87830dfd
......@@ -17,6 +17,7 @@ $Id$
+--------------------------------------------------------------------------*/
package org.fortiss.af3.mira.ui.editor;
import static java.awt.Desktop.getDesktop;
import static org.conqat.ide.commons.ui.dialog.MessageUtils.confirm;
import static org.eclipse.core.databinding.UpdateValueStrategy.POLICY_NEVER;
import static org.eclipse.jface.databinding.viewers.ViewersObservables.observeSinglePostSelection;
......@@ -35,6 +36,7 @@ import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.multiLineInputUnboun
import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.multiLineLabelFactory;
import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.singleLineInputFactory;
import static org.fortiss.af3.mira.ui.utils.MiraLayoutUtils.singleLineLabelFactory;
import static org.fortiss.af3.mira.utils.MiraModelElementFactory.createDocumentReference;
import static org.fortiss.af3.mira.utils.MiraModelElementFactory.createRequirement;
import static org.fortiss.af3.mira.utils.MiraModelElementFactory.createUseCase;
import static org.fortiss.af3.mira.utils.MiraUtils.getDisplayTypeFor;
......@@ -46,14 +48,22 @@ import static org.fortiss.tooling.kernel.ui.util.DataBindingUtils.DECORATION_KEY
import static org.fortiss.tooling.kernel.ui.util.DataBindingUtils.bind;
import static org.fortiss.tooling.kernel.ui.util.DataBindingUtils.performComplexTextBinding;
import static org.fortiss.tooling.kernel.ui.util.ObservableUtils.observeValue;
import static org.fortiss.tooling.kernel.utils.EcoreUtils.pickInstanceOf;
import static org.fortiss.tooling.kernel.utils.KernelModelElementUtils.getRootElements;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.conqat.ide.commons.ui.dialog.MessageUtils;
import org.eclipse.core.databinding.UpdateListStrategy;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.emf.databinding.EMFObservables;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.text.source.SourceViewer;
......@@ -63,11 +73,17 @@ import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
......@@ -77,14 +93,19 @@ import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.actions.TextStyledTextActionHandler;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.fortiss.af3.mira.model.Analysis;
import org.fortiss.af3.mira.model.Requirement;
import org.fortiss.af3.mira.model.RequirementPriority;
import org.fortiss.af3.mira.model.RequirementStatus;
import org.fortiss.af3.mira.model.glossary.Glossary;
import org.fortiss.af3.mira.model.requirementSource.FileItem;
import org.fortiss.af3.mira.model.requirementSource.RequirementDocument;
import org.fortiss.af3.mira.model.requirementSource.RequirementSource;
import org.fortiss.af3.mira.model.usecase.UseCase;
import org.fortiss.af3.mira.ui.AF3MiraUIActivator;
import org.fortiss.af3.mira.ui.action.ConvertRequirementAction;
import org.fortiss.af3.mira.ui.action.ReviewAction;
import org.fortiss.af3.mira.ui.action.ShowHierarchyAction;
......@@ -93,7 +114,11 @@ import org.fortiss.af3.mira.ui.editor.highlight.ListToWordRuleUpdateStrategy;
import org.fortiss.af3.mira.ui.editor.highlight.ScannerManager;
import org.fortiss.af3.mira.ui.editor.images.ImageSection;
import org.fortiss.af3.mira.ui.editor.relation.RelationSection;
import org.fortiss.af3.mira.ui.utils.RequirementUtils;
import org.fortiss.tooling.base.ui.dialog.ElementTreeSingleSelectDialog;
import org.fortiss.tooling.base.ui.dialog.ModelElementTreeContentProvider;
import org.fortiss.tooling.base.ui.editor.FormsEditorBase;
import org.fortiss.tooling.kernel.ui.presentation.ModelElementLabelProvider;
import org.fortiss.tooling.kernel.ui.service.IActionService;
/**
......@@ -400,6 +425,159 @@ public class RequirementEditor<T extends Requirement> extends FormsEditorBase<T>
singleLineInputFactory.applyTo(sourceInput.getControl());
bind(dbc, sourceInput.getTextWidget(), editedObject, REQUIREMENT__SOURCES);
/* edit Document Reference */
Label docrefLabel =
toolkit.createLabel(generalComposite, "Document Reference ", SWT.READ_ONLY);
singleLineLabelFactory.applyTo(docrefLabel);
Composite docrefEditPart = toolkit.createComposite(generalComposite);
docrefEditPart.setLayout(new GridLayout(4, false));
singleLineInputFactory.applyTo(docrefEditPart);
final Hyperlink docrefLink =
toolkit.createHyperlink(docrefEditPart,
RequirementUtils.toString(editedObject.getDocument()), SWT.NONE);
singleLineInputFactory.applyTo(docrefLink);
Button docrefEditButton = toolkit.createButton(docrefEditPart, "", SWT.FLAT);
docrefEditButton.setImage(AbstractUIPlugin.imageDescriptorFromPlugin(
AF3MiraUIActivator.PLUGIN_ID, "icons/Icon_add.png").createImage());
singleLineLabelFactory.applyTo(docrefEditButton);
Button docrefPageButton = toolkit.createButton(docrefEditPart, "Page", SWT.FLAT);
singleLineLabelFactory.applyTo(docrefPageButton);
Button docrefDeleteButton = toolkit.createButton(docrefEditPart, "", SWT.FLAT);
singleLineLabelFactory.applyTo(docrefDeleteButton);
docrefDeleteButton.setImage(AbstractUIPlugin.imageDescriptorFromPlugin(
AF3MiraUIActivator.PLUGIN_ID, "icons/Icon_delete.png").createImage());
docrefLink.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
try {
FileItem fileItem = editedObject.getDocument().getDocument();
File file = new File(fileItem.getUri());
// open the file in the system file viewer when the user
// double clicks on the link
if(fileItem.isIsLocal()) {
if(!RequirementUtils.openPDFWithPage(file, editedObject.getDocument()
.getPage()))
getDesktop().open(file);
} else {
getDesktop().browse(java.net.URI.create(fileItem.getUri()));
}
} catch(Exception e2) {
MessageUtils.showError("Open document", "Cannot open document");
}
}
});
docrefEditButton.addSelectionListener(new SelectionAdapter() {
/** {@inheritDoc} */
@Override
public void widgetSelected(SelectionEvent e) {
List<Analysis> analysises = getRootElements(editedObject, Analysis.class);
final ElementTreeSingleSelectDialog dialog =
new ElementTreeSingleSelectDialog(getSite().getShell(), analysises, null,
new ModelElementTreeContentProvider(analysises) {
/** {@inheritDoc} */
@Override
public List<? extends EObject> getChildren(EObject parent) {
if(parent instanceof Analysis) {
return pickInstanceOf(RequirementSource.class,
((Analysis)parent).getContainedElementsList());
} else if(parent instanceof RequirementSource) {
return pickInstanceOf(RequirementDocument.class,
((RequirementSource)parent)
.getContainedElementsList());
} else if(parent instanceof RequirementDocument) {
return pickInstanceOf(FileItem.class,
((RequirementDocument)parent)
.getContainedElementsList());
}
return Collections.emptyList();
}
}, new ModelElementLabelProvider() {
@Override
public String getText(Object element) {
if(element instanceof FileItem)
return RequirementUtils.toString((FileItem)element);
return super.getText(element);
}
}, null) {
/** {@inheritDoc} */
@Override
public boolean acceptElement(Object element) {
return element instanceof FileItem;
}
};
if(Window.OK != dialog.open())
return;
executeCommand(new Runnable() {
@Override
public void run() {
editedObject.setDocument(createDocumentReference(
(FileItem)dialog.getSelectedElement(), 1));
}
});
docrefLink.setText(RequirementUtils.toString(editedObject.getDocument()));
}
});
docrefPageButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
InputDialog inputDialog =
new InputDialog(getSite().getShell(), "Page number",
"Please input the page number:", "" +
editedObject.getDocument().getPage(),
new IInputValidator() {
@Override
public String isValid(String newText) {
try {
if(Integer.parseInt(newText) < 0) {
return "Hint: number must be greater than or equal to 0";
}
return null;
} catch(Exception e2) {
return "Hint: invalid number";
}
}
});
if(Window.OK != inputDialog.open())
return;
final int value = Integer.parseInt(inputDialog.getValue());
executeCommand(new Runnable() {
@Override
public void run() {
editedObject.setDocument(createDocumentReference(editedObject.getDocument()
.getDocument(), value));
}
});
docrefLink.setText(RequirementUtils.toString(editedObject.getDocument()));
}
});
docrefDeleteButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if(MessageUtils.confirm("Requriement Document", "Delete this reference?")) {
executeCommand(new Runnable() {
@Override
public void run() {
editedObject.setDocument(null);
}
});
docrefLink.setText("");
}
}
});
/* edit Requirement Status */
Label statusLabel = toolkit.createLabel(generalComposite, "Status ", SWT.READ_ONLY);
singleLineLabelFactory.applyTo(statusLabel);
......
......@@ -18,8 +18,6 @@ $Id: codetemplates.xml 1 2011-01-01 00:00:01Z hoelzl $
package org.fortiss.af3.mira.ui.editor.requirementSource;
import static java.awt.Desktop.getDesktop;
import static java.lang.String.format;
import static java.util.regex.Pattern.compile;
import static org.eclipse.emf.ecore.util.EcoreUtil.delete;
import static org.eclipse.jface.dialogs.MessageDialog.openQuestion;
import static org.eclipse.ui.plugin.AbstractUIPlugin.imageDescriptorFromPlugin;
......@@ -35,12 +33,12 @@ import static org.fortiss.tooling.kernel.ui.util.DataBindingUtils.bind;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.regex.Pattern;
import org.conqat.lib.commons.io.StreamReaderThread;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.text.source.SourceViewer;
......@@ -58,13 +56,14 @@ import org.eclipse.ui.actions.TextStyledTextActionHandler;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.fortiss.af3.mira.model.Analysis;
import org.fortiss.af3.mira.model.DocumentReference;
import org.fortiss.af3.mira.model.requirementSource.FileItem;
import org.fortiss.af3.mira.model.requirementSource.RequirementDocument;
import org.fortiss.af3.mira.model.requirementSource.RequirementSourcePackage;
import org.fortiss.af3.mira.ui.AF3MiraUIActivator;
import org.fortiss.af3.mira.ui.utils.RequirementUtils;
import org.fortiss.af3.project.ui.utils.NewProjectUtils;
import org.fortiss.tooling.kernel.service.ICommandStackService;
import org.fortiss.tooling.kernel.utils.LoggingUtils;
import org.fortiss.tooling.kernel.utils.KernelModelElementUtils;
/**
* GUI element for a single document file (saved as {@link FileItem}). It shows the file information
......@@ -163,8 +162,9 @@ public class FilePart {
singleLineLabelFactory.applyTo(linkLabel);
final Hyperlink link =
toolkit.createHyperlink(fileComposite,
fileItem.isIsLocal() ? file.getAbsolutePath() : fileItem.getUri(), SWT.NONE);
toolkit.createHyperlink(fileComposite, RequirementUtils.toString(fileItem),
SWT.NONE);
singleLineInputFactory.applyTo(link);
link.addMouseListener(new MouseAdapter() {
......@@ -175,10 +175,7 @@ public class FilePart {
// open the file in the system file viewer when the user
// double clicks on the link
if(isLocal) {
if(!file.getName().endsWith(".pdf") || fileItem.getPage() < 1 ||
!openPDFWithPage()) {
getDesktop().open(file);
}
getDesktop().open(file);
} else {
Desktop.getDesktop().browse(java.net.URI.create(fileItem.getUri()));
}
......@@ -287,18 +284,6 @@ public class FilePart {
singleLineInputFactory.applyTo(versionInput.getControl());
bind(dbc, versionInput.getControl(), fileItem, FILE_ITEM__VERSION);
// create version field
Label pageLabel = toolkit.createLabel(fileComposite, "Page ", SWT.READ_ONLY);
singleLineLabelFactory.applyTo(pageLabel);
final SourceViewer pageInput =
createSourceViewer(form, fileComposite, SWT.BORDER, document.getRequirementSource()
.getAnalysis());
registeredSourceViewers.add(pageInput);
singleLineInputFactory.applyTo(pageInput.getControl());
bind(dbc, pageInput.getControl(), fileItem,
RequirementSourcePackage.Literals.FILE_ITEM__PAGE);
// add styled handler
if(textStyledTextActionHandler != null) {
textStyledTextActionHandler.addText(descriptionInput.getTextWidget());
......@@ -338,6 +323,24 @@ public class FilePart {
ICommandStackService.INSTANCE.runAsCommand(document, new Runnable() {
@Override
public void run() {
HashSet<DocumentReference> refs = new HashSet<DocumentReference>();
for(Analysis a : KernelModelElementUtils.getRootElements(document, Analysis.class)) {
for(TreeIterator<EObject> iter = a.eAllContents(); iter.hasNext();) {
EObject e = iter.next();
if(e instanceof DocumentReference) {
DocumentReference d = (DocumentReference)e;
if(d.getDocument() == fileItem) {
refs.add(d);
}
}
}
}
for(DocumentReference ref : refs) {
delete(ref, true);
}
delete(fileItem, true);
}
});
......@@ -353,70 +356,4 @@ public class FilePart {
"Do you want to delete the reference to this file?");
}
/**
* Open a pdf file and jump to the specified page
*
* @return true if open and jump succeed, or false otherwise
*/
private boolean openPDFWithPage() {
try {
if(System.getProperty("os.name").startsWith("Windows")) {
Process process =
Runtime.getRuntime()
.exec("reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\AcroExch.Document\\Shell\\Open\\Command");
StreamReaderThread output = new StreamReaderThread(process.getInputStream());
if(process.waitFor() != 0)
throw new IllegalStateException("Cannot find acrobat reader.");
output.join();
String acrobat =
compile(".*REG_SZ\\s+\\\"(.*)\\\"\\s+\\\".*\\\"", Pattern.DOTALL).matcher(
output.getContent()).group(1);
if(Runtime
.getRuntime()
.exec(format("%s /A \"page=%d\" \"%s\"", acrobat, fileItem.getPage(),
file.getAbsoluteFile())).waitFor() != 0)
throw new IllegalStateException("Cannot launch acrobat reader.");
} else if(System.getProperty("os.name").contains("OS X")) {
// @CodeFormatterOff
String applescript =
"do shell script \"open -a Preview.app \\\"" + file.getAbsoluteFile() + "\\\"\" \n" +
"tell application \"Preview\" to activate \n" +
"tell application \"System Events\" to tell process \"Preview\" \n" +
" set PDFWindow to item 1 of (windows whose name starts with \""+file.getName()+"\") \n" +
" perform action \"AXRaise\" of PDFWindow \n" +
" keystroke \"g\" using {command down, option down} \n" +
" set value of text field 1 of sheet 1 of PDFWindow to \"" + fileItem.getPage() + "\" \n" +
" click button \"OK\" of sheet 1 of PDFWindow \n" +
"end tell \n";
// @CodeFormatterOn
LoggingUtils.info(AF3MiraUIActivator.getDefault(), applescript);
Process process = Runtime.getRuntime().exec("osascript");
StreamReaderThread reader = new StreamReaderThread(process.getErrorStream());
PrintWriter writer = new PrintWriter(process.getOutputStream());
writer.println(applescript);
writer.close();
reader.join();
if(process.waitFor() != 0)
throw new IllegalStateException("Cannot launch Preview. Error: " +
reader.getContent() + " Script: \n " + applescript);
} else {
if(Runtime
.getRuntime()
.exec(format("acroread /A \"page=%d\" \"%s\"", fileItem.getPage(),
file.getAbsoluteFile())).waitFor() != 0)
throw new IllegalStateException("Cannot launch acrobat reader.");
}
return true;
} catch(Exception e) {
LoggingUtils.info(AF3MiraUIActivator.getDefault(),
"failed to launch with PDF Reader, default application will be called.", e);
}
return false;
}
}
......@@ -17,18 +17,28 @@ $Id: codetemplates.xml 1 2011-01-01 00:00:01Z hoelzl $
+--------------------------------------------------------------------------*/
package org.fortiss.af3.mira.ui.utils;
import static java.lang.String.format;
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.conqat.lib.commons.io.StreamReaderThread;
import org.fortiss.af3.mira.model.DocumentReference;
import org.fortiss.af3.mira.model.Requirement;
import org.fortiss.af3.mira.model.requirementSource.FileItem;
import org.fortiss.af3.mira.model.requirementSource.RequirementSourceElement;
import org.fortiss.af3.mira.model.usecase.Actor;
import org.fortiss.af3.mira.model.usecase.Scenario;
import org.fortiss.af3.mira.model.usecase.ScenarioStep;
import org.fortiss.af3.mira.model.usecase.UseCase;
import org.fortiss.af3.mira.ui.AF3MiraUIActivator;
import org.fortiss.af3.project.ui.utils.NewProjectUtils;
import org.fortiss.tooling.base.utils.BaseModelElementUtils;
import org.fortiss.tooling.kernel.service.ICommandStackService;
import org.fortiss.tooling.kernel.utils.LoggingUtils;
/**
* Utility class for editing of {@link Requirement} and its children element
......@@ -201,4 +211,112 @@ public class RequirementUtils {
return null;
}
/**
* transform a {@link FileItem} to string
*
* @param item
* the {@link FileItem} to be transformed
* @return a string represents the given object
*/
public static String toString(FileItem item) {
if(item == null)
return "";
return item.isIsLocal() ? new File(NewProjectUtils.getDefaultGeneralProjectPath(),
item.getUri()).getAbsolutePath() : item.getUri();
}
/**
* transform a {@link DocumentReference} to string
*
* @param item
* the {@link DocumentReference} to be transformed
* @return a string represents the given object
*/
public static String toString(DocumentReference item) {
if(item == null)
return "";
String link = toString(item.getDocument());
if(item.getPage() > 1)
link += "#" + item.getPage();
return link;
}
/**
* Open a file and jump to the specified page
*
* @param file
* the file to be open
* @param page
* the page to be shown
* @return true if open action successes or false otherwise
*/
public static boolean openPDFWithPage(File file, int page) {
try {
Runtime runtime = Runtime.getRuntime();
if(System.getProperty("os.name").startsWith("Windows")) {
Process process =
runtime.exec("reg query HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\AcroExch.Document\\Shell\\Open\\Command");
StreamReaderThread output = new StreamReaderThread(process.getInputStream());
if(process.waitFor() != 0)
throw new IllegalStateException("Cannot find acrobat reader.");
output.join();
String regresult = output.getContent();
// String regresult =
// "\r\nHKEY_LOCAL_MACHINE\\SOFTWARE\\Classes\\AcroExch.Document\\Shell\\Open\\Command\r\n (Standard) REG_SZ \"c:\\Program Files (x86)\\Adobe\\Reader 10.0\\Reader\\AcroRd32.exe\" \"%1\"";
int indexstart = regresult.indexOf("REG_SZ");
int indexend = regresult.indexOf("\"%1\"");
if(indexstart == -1 || indexend == -1 || indexstart + 6 >= indexend)
throw new IllegalStateException("Cannot find acrobat reader.");
String acrobat = regresult.substring(indexstart + 6, indexend).trim();
if(runtime.exec(
format("%s /A \"page=%d\" \"%s\"", acrobat, page, file.getAbsoluteFile()))
.waitFor() != 0)
throw new IllegalStateException("Cannot launch acrobat reader.");
} else if(System.getProperty("os.name").contains("OS X")) {
// @CodeFormatterOff
String applescript =
"do shell script \"open -a Preview.app \\\"" + file.getAbsoluteFile() + "\\\"\" \n" +
"tell application \"Preview\" to activate \n" +
"tell application \"System Events\" to tell process \"Preview\" \n" +
" set PDFWindow to item 1 of (windows whose name starts with \""+file.getName()+"\") \n" +
" perform action \"AXRaise\" of PDFWindow \n" +
" keystroke \"g\" using {command down, option down} \n" +
" set value of text field 1 of sheet 1 of PDFWindow to \"" + page + "\" \n" +
" click button \"OK\" of sheet 1 of PDFWindow \n" +
"end tell \n";
// @CodeFormatterOn
LoggingUtils.info(AF3MiraUIActivator.getDefault(), applescript);
Process process = runtime.exec("osascript");
StreamReaderThread reader = new StreamReaderThread(process.getErrorStream());
PrintWriter writer = new PrintWriter(process.getOutputStream());
writer.println(applescript);
writer.close();
reader.join();
if(process.waitFor() != 0)
throw new IllegalStateException("Cannot launch Preview. Error: " +
reader.getContent() + " Script: \n " + applescript);
} else {
if(runtime.exec(
format("acroread /A \"page=%d\" \"%s\"", page, file.getAbsoluteFile()))
.waitFor() != 0 &&
runtime.exec(
format("xpdf /A \"page=%d\" \"%s\"", page, file.getAbsoluteFile()))
.waitFor() != 0)
throw new IllegalStateException("Cannot launch pdf reader.");
}
return true;
} catch(Exception e) {