Initial commit
This commit is contained in:
commit
44a36e5927
|
@ -0,0 +1,81 @@
|
|||
# Boilerplate .gitattributes
|
||||
#
|
||||
# If you add anything here that might be useful for other (new) projects,
|
||||
# consider changing ssh://git/git/template.git
|
||||
|
||||
* text=auto !eol
|
||||
|
||||
.*ignore text
|
||||
.gitignore text
|
||||
.gitattributes text
|
||||
|
||||
*.txt text
|
||||
*.java text diff=java
|
||||
*.html text diff=html
|
||||
*.css text
|
||||
*.js text
|
||||
*.ts text
|
||||
*.sql text
|
||||
*.properties text
|
||||
*.ipr text
|
||||
*.iml text
|
||||
*.iws text
|
||||
*.xml text
|
||||
*.form text
|
||||
*.dtd text
|
||||
*.xsl text
|
||||
*.xslt text
|
||||
*.plist text
|
||||
*.vm text
|
||||
*.install4j text
|
||||
|
||||
*.cs text diff=csharp
|
||||
*.csproj text merge=union
|
||||
*.sln text merge=union eol=crlf
|
||||
*.dsp text eol=crlf
|
||||
*.dsw text eol=crlf
|
||||
*.c text diff=cpp
|
||||
*.cpp text diff=cpp
|
||||
*.h text diff=cpp
|
||||
|
||||
*.php text diff=php
|
||||
*.py text diff=python
|
||||
|
||||
*.sh text eol=lf
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.lnk text eol=crlf
|
||||
Makefile text
|
||||
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.gif binary
|
||||
*.license binary
|
||||
*.jar binary
|
||||
*.zip binary
|
||||
*.exe binary
|
||||
*.bin binary
|
||||
*.dat binary
|
||||
*.bmp binary
|
||||
*.ico binary
|
||||
*.pdf binary
|
||||
|
||||
*.json text
|
||||
|
||||
*.jsbe text eol=crlf
|
||||
*.jsbp text eol=crlf
|
||||
*.jsbn text eol=crlf
|
||||
*.jsbh text eol=crlf
|
||||
*.jsbf text eol=crlf
|
||||
*.jsbc text eol=crlf
|
||||
|
||||
*.mp4 binary
|
||||
|
||||
*.soy text
|
||||
*.groovy text
|
||||
*.gant text
|
||||
|
||||
README text
|
||||
|
||||
*.pem text
|
||||
*.gpg text
|
|
@ -0,0 +1,3 @@
|
|||
build/
|
||||
build.idea/
|
||||
ant/generated.xml
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
<component name="PreferredVcsStorage">
|
||||
<preferredVcsName>ApexVCS</preferredVcsName>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8_112" project-jdk-type="JavaSDK" />
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/jiraclient.iml" filepath="$PROJECT_DIR$/.idea/jiraclient.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/../build.idea/AppInit" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.almworks.appinit;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public interface AWTEventPreprocessor {
|
||||
boolean preprocess(AWTEvent event, boolean alreadyConsumed);
|
||||
|
||||
boolean postProcess(AWTEvent event, boolean alreadyConsumed);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.almworks.appinit;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
public class EventQueueReplacement extends EventQueue {
|
||||
// @Nullable
|
||||
private static EventQueueReplacement INSTANCE;
|
||||
private final java.util.List<AWTEventPreprocessor> myPreprocessors = new ArrayList();
|
||||
private AWTEventPreprocessor[] myArray;
|
||||
|
||||
private EventQueueReplacement() {
|
||||
}
|
||||
|
||||
// @ThreadSafe
|
||||
public void addPreprocessor(final AWTEventPreprocessor preprocessor) {
|
||||
synchronized (myPreprocessors) {
|
||||
myPreprocessors.add(preprocessor);
|
||||
resetArray();
|
||||
}
|
||||
}
|
||||
|
||||
private void resetArray() {
|
||||
int size = myPreprocessors.size();
|
||||
myArray = size == 0 ? null : myPreprocessors.toArray(new AWTEventPreprocessor[size]);
|
||||
}
|
||||
|
||||
// @ThreadSafe
|
||||
public boolean removePreprocessor(AWTEventPreprocessor preprocessor) {
|
||||
synchronized (myPreprocessors) {
|
||||
boolean result = myPreprocessors.remove(preprocessor);
|
||||
resetArray();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
protected void dispatchEvent(AWTEvent event) {
|
||||
boolean consumed = false;
|
||||
AWTEventPreprocessor[] array = myArray;
|
||||
if (array != null) {
|
||||
for (AWTEventPreprocessor preprocessor : array) {
|
||||
consumed = preprocessor.preprocess(event, consumed);
|
||||
if (consumed) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!consumed) {
|
||||
super.dispatchEvent(event);
|
||||
}
|
||||
consumed = consumed || ((event instanceof InputEvent) && ((InputEvent) event).isConsumed());
|
||||
if (array != null && !consumed) {
|
||||
for (AWTEventPreprocessor processor : array) {
|
||||
consumed = processor.postProcess(event, consumed);
|
||||
if (consumed) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @NotNull
|
||||
public static EventQueueReplacement ensureInstalled() {
|
||||
synchronized (EventQueueReplacement.class) {
|
||||
if (INSTANCE != null) return INSTANCE;
|
||||
}
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (EventQueueReplacement.class) {
|
||||
if (INSTANCE == null) {
|
||||
EventQueueReplacement queue = new EventQueueReplacement();
|
||||
Toolkit.getDefaultToolkit().getSystemEventQueue().push(queue);
|
||||
INSTANCE = queue;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (EventQueue.isDispatchThread()) {
|
||||
// Install event queue in separate invocation event. Otherwise previous AWT thread become not-AWT, so AWT confined object may be accessed from two threads (old AWT and new AWT).
|
||||
// Code in both threads may check the thread and get the confirmation.
|
||||
// To avoid such problems:
|
||||
// 1. Install event queue from current AWT thread. This ensures that no other code is executed in AWT thread, no AWT confined objects can be accessed right during event queue
|
||||
// replacement.
|
||||
// 2. Install event queue in separate invocation event. Avoid any activity before and especially after event queue replacement. Since this thread is not AWT thread any more.
|
||||
// This check logs error if it can not control right event queue replacement.
|
||||
Logger.getLogger("").log(Level.WARNING, "Install event queue from not dispatch thread", new Throwable());
|
||||
runnable.run();
|
||||
}
|
||||
else try {
|
||||
SwingUtilities.invokeAndWait(runnable);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
synchronized (EventQueueReplacement.class) {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public static void detachPreprocessor(AWTEventPreprocessor preprocessor) {
|
||||
EventQueueReplacement instance;
|
||||
synchronized (EventQueueReplacement.class) {
|
||||
instance = INSTANCE;
|
||||
if (instance == null)
|
||||
return;
|
||||
}
|
||||
instance.removePreprocessor(preprocessor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module relativePaths="true" type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<output url="file://$MODULE_DIR$/../build.idea/Application" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="junit" level="project" />
|
||||
<orderEntry type="library" name="picocontainer" level="project" />
|
||||
<orderEntry type="module" module-name="Utils" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="file://$MODULE_DIR$/rc" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="module" module-name="CoreComponents" exported="" />
|
||||
<orderEntry type="module" module-name="Engine" exported="" />
|
||||
<orderEntry type="module" module-name="Launcher" />
|
||||
<orderEntry type="library" name="jetbrains-annotations" level="project" />
|
||||
<orderEntry type="module" module-name="Services" exported="" />
|
||||
<orderEntry type="library" name="jgoodies-forms" level="project" />
|
||||
<orderEntry type="module" module-name="CommonUtils" />
|
||||
<orderEntry type="module" module-name="Screenshot" />
|
||||
<orderEntry type="module" module-name="CommonUtils" />
|
||||
<orderEntry type="library" name="itext" level="project" />
|
||||
<orderEntry type="library" name="jna" level="project" />
|
||||
<orderEntry type="module" module-name="ItemStorage" />
|
||||
<orderEntry type="module" module-name="ItemSync" />
|
||||
<orderEntry type="module" module-name="ItemGUI" />
|
||||
<orderEntry type="module" module-name="widgets" />
|
||||
</component>
|
||||
<component name="RetroweaverPlugin">
|
||||
<setting name="active" value="true" />
|
||||
<setting name="verbose" value="false" />
|
||||
<setting name="verifyrefs" value="true" />
|
||||
<setting name="targetJDK" value="1.4" />
|
||||
</component>
|
||||
</module>
|
|
@ -0,0 +1,81 @@
|
|||
<!DOCTYPE ui [
|
||||
<!ELEMENT viewer (id,presentation,componentFactory,componentBinding)>
|
||||
<!ELEMENT componentBinding (actionBinding*, modelBinding*, sameNames?)>
|
||||
<!ELEMENT sameNames (#PCDATA)>
|
||||
<!ELEMENT actionBinding (componentName, browseWeb)>
|
||||
<!ELEMENT modelBinding (componentName, key)>
|
||||
<!ELEMENT browseWeb (#PCDATA)>
|
||||
<!ELEMENT presentation (Name)>
|
||||
<!ELEMENT sizePolicy (srinkable)>
|
||||
<!ELEMENT prototype (property)+>
|
||||
<!ELEMENT property (key,value)>
|
||||
<!ELEMENT srinkable (#PCDATA)>
|
||||
<!ELEMENT componentFactory (className,instanceFieldName)>
|
||||
<!ELEMENT mainColumns (column)+>
|
||||
<!ELEMENT column (key,sizePolicy?)>
|
||||
<!ELEMENT ui (viewers,mainProperty,mainColumns,prototype)>
|
||||
<!ELEMENT viewers (viewer)+>
|
||||
<!ELEMENT id (#PCDATA)>
|
||||
<!ELEMENT key (#PCDATA)>
|
||||
<!ELEMENT componentName (#PCDATA)>
|
||||
<!ELEMENT className (#PCDATA)>
|
||||
<!ELEMENT instanceFieldName (#PCDATA)>
|
||||
<!ELEMENT Name (#PCDATA)>
|
||||
<!ELEMENT mainProperty (#PCDATA)>
|
||||
<!ELEMENT value (#PCDATA)>
|
||||
<!ELEMENT browseActionKey (#PCDATA)>
|
||||
]>
|
||||
<ui>
|
||||
<viewers>
|
||||
<viewer>
|
||||
<id>system</id>
|
||||
<presentation>
|
||||
<Name>System</Name>
|
||||
</presentation>
|
||||
<componentFactory>
|
||||
<className>com.almworks.explorer.view.SystemView</className>
|
||||
<instanceFieldName>myWholePanel</instanceFieldName>
|
||||
</componentFactory>
|
||||
</viewer>
|
||||
</viewers>
|
||||
<mainProperty>name</mainProperty>
|
||||
<mainColumns>
|
||||
<column>
|
||||
<key>name</key>
|
||||
</column>
|
||||
<column>
|
||||
<key>type</key>
|
||||
</column>
|
||||
<column>
|
||||
<key>description</key>
|
||||
</column>
|
||||
<column>
|
||||
<key>key</key>
|
||||
</column>
|
||||
<column>
|
||||
<key>ID</key>
|
||||
</column>
|
||||
</mainColumns>
|
||||
<prototype>
|
||||
<property>
|
||||
<key>name</key>
|
||||
<value>Array of references</value>
|
||||
</property>
|
||||
<property>
|
||||
<key>type</key>
|
||||
<value>Value Type</value>
|
||||
</property>
|
||||
<property>
|
||||
<key>description</key>
|
||||
<value>Values of this type are arrays of values of type Reference</value>
|
||||
</property>
|
||||
<property>
|
||||
<key>key</key>
|
||||
<value>2.3.4.5.6.7.</value>
|
||||
</property>
|
||||
<property>
|
||||
<key>ID</key>
|
||||
<value>tracker:whatever:address:could:be:here</value>
|
||||
</property>
|
||||
</prototype>
|
||||
</ui>
|
|
@ -0,0 +1,2 @@
|
|||
sumtable.configurations.duplicateName.name={1}{0,choice,0#|0< {0}}
|
||||
sumtable.configurations.duplicateName.applied=(.*)\\s(\\d+)
|
|
@ -0,0 +1 @@
|
|||
sysprop.window.seedoc.text=See system properties reference
|
|
@ -0,0 +1,57 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.application.tree.ConnectionNode;
|
||||
import com.almworks.api.application.tree.GenericNode;
|
||||
import com.almworks.api.engine.Connection;
|
||||
import com.almworks.api.search.TextSearchUtils;
|
||||
import com.almworks.util.commons.FunctionE;
|
||||
import com.almworks.util.ui.actions.ActionContext;
|
||||
import com.almworks.util.ui.actions.CantPerformException;
|
||||
import com.almworks.util.ui.actions.SimpleAction;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ConnectionAction extends SimpleAction {
|
||||
public static final FunctionE<ActionContext, Connection, CantPerformException> SELECTED_NODE =
|
||||
new FunctionE<ActionContext, Connection, CantPerformException>() {
|
||||
@Override
|
||||
public Connection invoke(ActionContext context) throws CantPerformException {
|
||||
final List<GenericNode> nodes = context.getSourceCollection(GenericNode.NAVIGATION_NODE);
|
||||
return getConnection(nodes);
|
||||
}
|
||||
};
|
||||
|
||||
public static final FunctionE<ActionContext, Connection, CantPerformException> PARENT_NODE =
|
||||
new FunctionE<ActionContext, Connection, CantPerformException>() {
|
||||
@Override
|
||||
public Connection invoke(ActionContext context) throws CantPerformException {
|
||||
final Collection<GenericNode>
|
||||
nodes = TextSearchUtils.escalateToConnectionNodes(context.getSourceCollection(GenericNode.NAVIGATION_NODE));
|
||||
return getConnection(nodes);
|
||||
}
|
||||
};
|
||||
|
||||
private static Connection getConnection(Collection<GenericNode> nodes) {
|
||||
if(nodes == null || nodes.size() != 1) {
|
||||
return null;
|
||||
}
|
||||
final GenericNode node = nodes.iterator().next();
|
||||
if(node instanceof ConnectionNode) {
|
||||
return node.getConnection();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final FunctionE<ActionContext, Connection, CantPerformException> myConnectionExtractor;
|
||||
|
||||
protected ConnectionAction(@Nullable String name, FunctionE<ActionContext, Connection, CantPerformException> connectionExtractor) {
|
||||
super(name);
|
||||
myConnectionExtractor = connectionExtractor;
|
||||
}
|
||||
|
||||
protected Connection extractConnection(ActionContext context) throws CantPerformException {
|
||||
return myConnectionExtractor.invoke(context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.application.ItemWrapper;
|
||||
import com.almworks.api.application.LoadedItemServices;
|
||||
import com.almworks.api.engine.Connection;
|
||||
import com.almworks.integers.LongArray;
|
||||
import com.almworks.integers.LongList;
|
||||
import com.almworks.integers.LongListIterator;
|
||||
import com.almworks.integers.WritableLongList;
|
||||
import com.almworks.items.api.DBReader;
|
||||
import com.almworks.items.api.Database;
|
||||
import com.almworks.items.api.ReadTransaction;
|
||||
import com.almworks.items.sync.util.SyncUtils;
|
||||
import com.almworks.util.Terms;
|
||||
import com.almworks.util.commons.Procedure;
|
||||
import com.almworks.util.exec.ThreadGate;
|
||||
import com.almworks.util.i18n.Local;
|
||||
import com.almworks.util.ui.UIUtil;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.almworks.util.Collections15.hashMap;
|
||||
|
||||
public class CopyIdAndSummaryAction extends SimpleAction {
|
||||
public CopyIdAndSummaryAction() {
|
||||
super("C&opy ID && Summary");
|
||||
setDefaultPresentation(PresentationKey.SHORT_DESCRIPTION, "Copy ID and Summary of selected " + Terms.ref_artifacts + " to clipboard");
|
||||
setDefaultPresentation(PresentationKey.ENABLE, EnableState.DISABLED);
|
||||
setDefaultPresentation(PresentationKey.SHORTCUT,
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
|
||||
watchRole(ItemWrapper.ITEM_WRAPPER);
|
||||
}
|
||||
|
||||
public static Map<Connection, LongList> getItemsGroupedByConnection(ActionContext context) throws CantPerformException {
|
||||
List<ItemWrapper> wrappers = context.getSourceCollection(ItemWrapper.ITEM_WRAPPER);
|
||||
Map<Connection, LongList> result = hashMap();
|
||||
for (ItemWrapper wrapper : wrappers) {
|
||||
LoadedItemServices services = wrapper.services();
|
||||
if (services.isDeleted())
|
||||
continue;
|
||||
Connection connection = wrapper.getConnection();
|
||||
if (connection != null && !connection.getState().getValue().isDegrading()) {
|
||||
WritableLongList target = (WritableLongList) result.get(connection);
|
||||
if (target == null) {
|
||||
target = new LongArray();
|
||||
result.put(connection, target);
|
||||
}
|
||||
target.add(services.getItem());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void doPerform(ActionContext context) throws CantPerformException {
|
||||
final Map<Connection, LongList> map = getItemsGroupedByConnection(context);
|
||||
context.getSourceObject(Database.ROLE).readForeground(new ReadTransaction<StringBuilder>() {
|
||||
public StringBuilder transaction(DBReader reader) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean multiple = false;
|
||||
for (Map.Entry<Connection, LongList> e : map.entrySet()) {
|
||||
Connection connection = e.getKey();
|
||||
for (LongListIterator i = e.getValue().iterator(); i.hasNext();) {
|
||||
String s = connection.getExternalIdSummaryString(SyncUtils.readTrunk(reader, i.nextValue()));
|
||||
if (s != null && s.length() > 0) {
|
||||
if (result.length() > 0) {
|
||||
result.append('\n');
|
||||
multiple = true;
|
||||
}
|
||||
result.append(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (multiple)
|
||||
result.append('\n');
|
||||
return result;
|
||||
}
|
||||
}).onSuccess(ThreadGate.AWT, new Procedure<StringBuilder>() {
|
||||
public void invoke(StringBuilder arg) {
|
||||
if (arg.length() == 0)
|
||||
return;
|
||||
UIUtil.copyToClipboard(arg.toString());
|
||||
Toolkit.getDefaultToolkit().beep();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
int count = 0;
|
||||
try {
|
||||
List<ItemWrapper> wrappers = context.getSourceCollection(ItemWrapper.ITEM_WRAPPER);
|
||||
for (ItemWrapper wrapper : wrappers) {
|
||||
if (wrapper.services().isDeleted())
|
||||
return;
|
||||
Connection connection = wrapper.getConnection();
|
||||
if (connection == null || connection.getState().getValue().isDegrading())
|
||||
return;
|
||||
count++;
|
||||
}
|
||||
context.setEnabled(count > 0);
|
||||
} finally {
|
||||
if (count != 1) {
|
||||
context.putPresentationProperty(PresentationKey.SHORT_DESCRIPTION,
|
||||
Local.parse("Copy to clipboard IDs and summaries of the selected " + Terms
|
||||
.ref_artifacts));
|
||||
} else {
|
||||
context.putPresentationProperty(PresentationKey.SHORT_DESCRIPTION,
|
||||
Local.parse("Copy to clipboard ID and summary of the selected " + Terms
|
||||
.ref_artifact));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.application.tree.GenericNode;
|
||||
import com.almworks.api.application.tree.TreeNodeFactory;
|
||||
import com.almworks.util.components.ACollectionComponent;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
class CreateChildNodeAction extends SimpleAction {
|
||||
private final TreeNodeFactory.NodeType myNodeType;
|
||||
|
||||
private CreateChildNodeAction(Icon icon, TreeNodeFactory.NodeType type) {
|
||||
super((String)null, icon);
|
||||
myNodeType = type;
|
||||
watchRole(GenericNode.NAVIGATION_NODE);
|
||||
setDefaultPresentation(PresentationKey.ENABLE, EnableState.INVISIBLE);
|
||||
}
|
||||
|
||||
protected void doPerform(ActionContext context) throws CantPerformException {
|
||||
ComponentContext<ACollectionComponent> componentContext =
|
||||
context.getComponentContext(ACollectionComponent.class, GenericNode.NAVIGATION_NODE);
|
||||
TreeNodeFactory nodeFactory = context.getSourceObject(TreeNodeFactory.TREE_NODE_FACTORY);
|
||||
GenericNode parent = getGenericNodeImpl(componentContext);
|
||||
nodeFactory.createAndEditNode(parent, myNodeType, context);
|
||||
}
|
||||
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
context.getSourceObject(TreeNodeFactory.TREE_NODE_FACTORY);
|
||||
ComponentContext<ACollectionComponent> componentContext =
|
||||
context.getComponentContext(ACollectionComponent.class, GenericNode.NAVIGATION_NODE);
|
||||
GenericNode node = getGenericNodeImpl(componentContext);
|
||||
if (node.allowsChildren(myNodeType))
|
||||
context.setEnabled(EnableState.ENABLED);
|
||||
}
|
||||
|
||||
public static CreateChildNodeAction create(TreeNodeFactory.NodeType type) {
|
||||
return new CreateChildNodeAction(null, type);
|
||||
}
|
||||
|
||||
public static CreateChildNodeAction create(Icon icon, TreeNodeFactory.NodeType type) {
|
||||
return new CreateChildNodeAction(icon, type);
|
||||
}
|
||||
|
||||
public static GenericNode getGenericNodeImpl(ComponentContext<?> context) throws CantPerformException {
|
||||
return context.getSourceObject(GenericNode.NAVIGATION_NODE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.actions.ItemActionUtils;
|
||||
import com.almworks.api.application.ItemWrapper;
|
||||
import com.almworks.api.engine.Engine;
|
||||
import com.almworks.api.engine.ItemSyncProblem;
|
||||
import com.almworks.api.engine.Synchronizer;
|
||||
import com.almworks.integers.LongArray;
|
||||
import com.almworks.integers.LongList;
|
||||
import com.almworks.integers.LongListIterator;
|
||||
import com.almworks.integers.WritableLongListIterator;
|
||||
import com.almworks.items.api.DBOperationCancelledException;
|
||||
import com.almworks.items.api.DBReader;
|
||||
import com.almworks.items.sync.*;
|
||||
import com.almworks.items.sync.util.ItemValues;
|
||||
import com.almworks.items.sync.util.SyncUtils;
|
||||
import com.almworks.util.AppBook;
|
||||
import com.almworks.util.Terms;
|
||||
import com.almworks.util.commons.Condition;
|
||||
import com.almworks.util.exec.ThreadGate;
|
||||
import com.almworks.util.i18n.LText1;
|
||||
import com.almworks.util.i18n.LText2;
|
||||
import com.almworks.util.i18n.Local;
|
||||
import com.almworks.util.images.Icons;
|
||||
import com.almworks.util.ui.DialogsUtil;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
import gnu.trove.TLongObjectHashMap;
|
||||
import org.almworks.util.Log;
|
||||
import util.concurrent.SynchronizedBoolean;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author dyoma
|
||||
*/
|
||||
public class DiscardLocalChangesAction extends SimpleAction {
|
||||
private static final String PREFIX = "Application.Actions.";
|
||||
private static final Condition<ItemWrapper> DISCARDABLE_ITEM = new Condition<ItemWrapper>() {
|
||||
public boolean isAccepted(ItemWrapper wrapper) {
|
||||
return wrapper.getDBStatus().isDiscardable();
|
||||
}
|
||||
};
|
||||
|
||||
public DiscardLocalChangesAction() {
|
||||
super("Discard &Changes", Icons.ACTION_DISCARD);
|
||||
}
|
||||
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
context.watchModifiableRole(SyncManager.MODIFIABLE);
|
||||
ItemActionUtils.basicUpdate(context, true);
|
||||
|
||||
SyncManager syncMan = context.getSourceObject(SyncManager.ROLE);
|
||||
List<ItemWrapper> items = getItemWrappers(context);
|
||||
int count = items.size();
|
||||
for (ItemWrapper item : items) {
|
||||
if (syncMan.findLock(item.getItem()) != null || item.services().isLockedForUpload()) {
|
||||
count--;
|
||||
} else {
|
||||
LongList slaves = item.getMetaInfo().getSlavesToDiscard(item);
|
||||
if (syncMan.findAnyLock(slaves) != null) count--;
|
||||
}
|
||||
}
|
||||
context.setEnabled(count > 0);
|
||||
}
|
||||
|
||||
protected void doPerform(ActionContext context) throws CantPerformException {
|
||||
final SyncManager syncMan = context.getSourceObject(SyncManager.ROLE);
|
||||
|
||||
final LongArray items = new LongArray();
|
||||
int discarding = 0, removing = 0;
|
||||
for(final ItemWrapper iw : getItemWrappers(context)) {
|
||||
final long item = iw.getItem();
|
||||
if(syncMan.findLock(item) == null) {
|
||||
items.add(item);
|
||||
if(iw.getDBStatus() == ItemWrapper.DBStatus.DB_NEW) {
|
||||
removing++;
|
||||
} else {
|
||||
discarding++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CantPerformException.ensure(!items.isEmpty());
|
||||
|
||||
final Component component = context.getComponent();
|
||||
final String confirmationMsg = createConfirmationMessage(discarding, removing);
|
||||
final Synchronizer sync = context.getSourceObject(Engine.ROLE).getSynchronizer();
|
||||
|
||||
CantPerformException.ensure(
|
||||
CantPerformException.ensureNotNull(syncMan.prepareEdit(items)).start(new MyDiscardFactory(component, confirmationMsg, sync)));
|
||||
}
|
||||
|
||||
private static EditCommit createDiscardCommit(final LongArray items, final Synchronizer sync, final SynchronizedBoolean alive) {
|
||||
return new EditCommit() {
|
||||
@Override
|
||||
public void performCommit(EditDrain drain) {
|
||||
for (WritableLongListIterator i = items.iterator(); i.hasNext();) {
|
||||
long primary = i.nextValue();
|
||||
boolean discardSucceeded = drain.discardChanges(primary);
|
||||
if (!discardSucceeded) {
|
||||
Log.warn("discard did not succeed for item " + primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommitFinished(boolean success) {
|
||||
if(success) {
|
||||
ThreadGate.AWT_QUEUED.execute(new Runnable() { public void run() {
|
||||
for (WritableLongListIterator i = items.iterator(); i.hasNext();) {
|
||||
removeProblem(i.nextValue(), sync);
|
||||
}
|
||||
}});
|
||||
} else {
|
||||
alive.set(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "DiscardLocalChangesAction";
|
||||
}
|
||||
|
||||
private static boolean confirmDiscard(Component component, String message) {
|
||||
Component c = component == null ? null : SwingUtilities.getWindowAncestor(component);
|
||||
return (DialogsUtil.YES_OPTION == DialogsUtil.askUser(c, message, "Discard Changes", DialogsUtil.YES_NO_OPTION));
|
||||
}
|
||||
|
||||
private static String createConfirmationMessage(int discardCount, int removeCount) {
|
||||
final String message;
|
||||
if(discardCount > 0 && removeCount == 0) {
|
||||
message = DISCARD_CONFIRM().format(discardCount);
|
||||
} else if (discardCount == 0 && removeCount > 0) {
|
||||
message = REMOVE_CONFIRM().format(removeCount);
|
||||
} else {
|
||||
message = MIXED_CONFIRM().format(discardCount, removeCount);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
private static LText1<Integer> REMOVE_CONFIRM() {
|
||||
return AppBook.text(PREFIX + "REMOVE_CONFIRM", Local.parse(
|
||||
"Are you sure you want to remove {0,choice,1#this $(" + Terms.key_artifact + ")|1<these {0,number} " +
|
||||
Terms.ref_artifacts + "}?"), 0);
|
||||
}
|
||||
|
||||
private static LText1<Integer> DISCARD_CONFIRM() {
|
||||
return AppBook.text(PREFIX + "DISCARD_CONFIRM", Local.parse(
|
||||
"Are you sure you want to discard {0,choice,1#changes|1<the changes to {0,number} " + Terms.ref_artifacts + "}?"),
|
||||
0);
|
||||
}
|
||||
|
||||
private static LText2<Integer, Integer> MIXED_CONFIRM() {
|
||||
return AppBook.text(PREFIX + "MIXED_CONFIRM", Local.parse(
|
||||
"Are you sure you want to discard the changes to {0,number} " + Terms.ref_artifacts + " and to remove " +
|
||||
"{1, number} new " + Terms.ref_artifacts + "?"), 0, 0);
|
||||
}
|
||||
|
||||
private static List<ItemWrapper> getItemWrappers(ActionContext context) throws CantPerformException {
|
||||
List<ItemWrapper> wrappers = context.getSourceCollection(ItemWrapper.ITEM_WRAPPER);
|
||||
return DISCARDABLE_ITEM.filterList(wrappers);
|
||||
}
|
||||
|
||||
private static void removeProblem(long item, Synchronizer synchronizer) {
|
||||
if (synchronizer != null) {
|
||||
for (ItemSyncProblem problem : synchronizer.getItemProblems(item)) {
|
||||
problem.disappear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class DiscardEditor implements ItemEditor {
|
||||
private final SynchronizedBoolean myAlive;
|
||||
private final Component myComponent;
|
||||
private final String myConfirmationMsg;
|
||||
private final LongArray myItemsToDiscard;
|
||||
private final Synchronizer mySync;
|
||||
private final EditControl myEditControl;
|
||||
|
||||
public DiscardEditor(Component component, String confirmationMsg, LongArray itemsToDiscard, Synchronizer sync, EditControl editControl, SynchronizedBoolean aliveFlag) {
|
||||
myComponent = component;
|
||||
myConfirmationMsg = confirmationMsg;
|
||||
myItemsToDiscard = itemsToDiscard;
|
||||
mySync = sync;
|
||||
myEditControl = editControl;
|
||||
myAlive = aliveFlag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showEditor() throws CantPerformException {
|
||||
if (!confirmDiscard(myComponent, myConfirmationMsg)) throw new CantPerformExceptionSilently("Rejected");
|
||||
ThreadGate.AWT_QUEUED.execute(new Runnable() { public void run() {
|
||||
myEditControl.commit(createDiscardCommit(myItemsToDiscard, mySync, myAlive));
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return myAlive.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() throws CantPerformException {}
|
||||
|
||||
@Override
|
||||
public void onEditReleased() {}
|
||||
|
||||
@Override
|
||||
public void onItemsChanged(TLongObjectHashMap<ItemValues> newValues) {}
|
||||
}
|
||||
|
||||
|
||||
private static class MyDiscardFactory implements EditorFactory {
|
||||
private final Component myComponent;
|
||||
private final String myConfirmationMsg;
|
||||
private final Synchronizer mySync;
|
||||
private final SynchronizedBoolean myAliveFlag = new SynchronizedBoolean(true);
|
||||
|
||||
public MyDiscardFactory(Component component, String confirmationMsg, Synchronizer sync) {
|
||||
myComponent = component;
|
||||
myConfirmationMsg = confirmationMsg;
|
||||
mySync = sync;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editCancelled() {
|
||||
myAliveFlag.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemEditor prepareEdit(DBReader reader, final EditPrepare prepare) throws DBOperationCancelledException {
|
||||
LongArray primaryItems = LongArray.copy(prepare.getItems());
|
||||
final LongArray itemsToDiscard = new LongArray(primaryItems.size());
|
||||
for (LongListIterator i = primaryItems.iterator(); i.hasNext();) {
|
||||
long primary = i.nextValue();
|
||||
LongList subtree = SyncUtils.getSlavesSubtree(reader, primary);
|
||||
if (prepare.addItems(subtree)) {
|
||||
itemsToDiscard.add(primary);
|
||||
}
|
||||
}
|
||||
if (itemsToDiscard.isEmpty()) return null;
|
||||
return new DiscardEditor(myComponent, myConfirmationMsg, itemsToDiscard, mySync, prepare.getControl(), myAliveFlag);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.actions.ItemActionUtils;
|
||||
import com.almworks.api.application.*;
|
||||
import com.almworks.api.engine.Connection;
|
||||
import com.almworks.api.engine.Engine;
|
||||
import com.almworks.api.engine.SyncTask;
|
||||
import com.almworks.api.engine.Synchronizer;
|
||||
import com.almworks.integers.LongList;
|
||||
import com.almworks.integers.LongListIterator;
|
||||
import com.almworks.util.L;
|
||||
import com.almworks.util.Terms;
|
||||
import com.almworks.util.collections.MultiMap;
|
||||
import com.almworks.util.collections.PrimitiveUtils;
|
||||
import com.almworks.util.collections.SimpleModifiable;
|
||||
import com.almworks.util.commons.Condition;
|
||||
import com.almworks.util.images.Icons;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class DownloadItemAction extends SimpleAction {
|
||||
private static final Condition<ItemWrapper> CAN_DOWNLOAD = new CanDownload();
|
||||
private static final Condition<ItemWrapper> HAS_DETAILS = new HasDetails();
|
||||
|
||||
private static final String DOWNLOAD_SHORT = L.actionName("&Download All Details");
|
||||
private static final String RELOAD_SHORT = L.actionName("Reload All &Details");
|
||||
|
||||
private static final String DOWNLOAD_LONG = L.tooltip("Download all details for selected " + Terms.ref_artifacts);
|
||||
private static final String RELOAD_LONG = L.tooltip("Re-download all details for selected " + Terms.ref_artifacts);
|
||||
|
||||
private static final String DOWNLOADING = L.actionName("Downloading\u2026");
|
||||
private static final String RELOADING = L.actionName("Reloading\u2026");
|
||||
|
||||
private final Synchronizer mySync;
|
||||
private boolean myPreToggle;
|
||||
private final SimpleModifiable myPreToggleModifiable = new SimpleModifiable();
|
||||
|
||||
public DownloadItemAction(Engine engine) {
|
||||
super(L.actionName(DOWNLOAD_SHORT), Icons.ACTION_UPDATE_ARTIFACT);
|
||||
setDefaultPresentation(PresentationKey.ENABLE, EnableState.DISABLED);
|
||||
mySync = engine.getSynchronizer();
|
||||
updateOnChange(mySync.getTasksModifiable());
|
||||
updateOnChange(myPreToggleModifiable);
|
||||
}
|
||||
|
||||
private static MultiMap<Connection, ItemWrapper> getItemWrappersGroupedByConnection(ActionContext context)
|
||||
throws CantPerformException
|
||||
{
|
||||
List<ItemWrapper> wrappers = context.getSourceCollection(ItemWrapper.ITEM_WRAPPER);
|
||||
MultiMap<Connection, ItemWrapper> result = MultiMap.create();
|
||||
for (ItemWrapper wrapper : wrappers) {
|
||||
if (wrapper.services().isRemoteDeleted())
|
||||
continue;
|
||||
Connection connection = wrapper.getConnection();
|
||||
if (connection != null && !connection.getState().getValue().isDegrading()) {
|
||||
result.add(connection, wrapper);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void doPerform(ActionContext context) throws CantPerformException {
|
||||
MultiMap<Connection, ItemWrapper> map = getItemWrappersGroupedByConnection(context);
|
||||
for (Connection connection : map.keySet()) {
|
||||
LongList items = PrimitiveUtils.selectThenCollect(CAN_DOWNLOAD, ItemWrapper.GET_ITEM, map.getAll(connection));
|
||||
if (!items.isEmpty()) {
|
||||
connection.downloadItemDetails(items);
|
||||
myPreToggle = true;
|
||||
}
|
||||
}
|
||||
if (myPreToggle) myPreToggleModifiable.fireChanged();
|
||||
}
|
||||
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
final List<ItemWrapper> wrappers = ItemActionUtils.basicUpdate(context, false);
|
||||
|
||||
boolean enabled = false;
|
||||
String name = DOWNLOAD_SHORT;
|
||||
String ongoing = DOWNLOADING;
|
||||
String expl = DOWNLOAD_LONG;
|
||||
|
||||
final List<ItemWrapper> updatable = CAN_DOWNLOAD.filterList(wrappers);
|
||||
if(!updatable.isEmpty()) {
|
||||
enabled = true;
|
||||
|
||||
final List<ItemWrapper> reloadable = HAS_DETAILS.filterList(updatable);
|
||||
if(reloadable.size() == updatable.size()) {
|
||||
name = RELOAD_SHORT;
|
||||
ongoing = RELOADING;
|
||||
expl = RELOAD_LONG;
|
||||
}
|
||||
}
|
||||
|
||||
context.setEnabled(enabled);
|
||||
|
||||
if(areBeingDownloaded(wrappers) || getPreToggledAndClear()) {
|
||||
context.putPresentationProperty(PresentationKey.NAME, ongoing);
|
||||
context.putPresentationProperty(PresentationKey.SMALL_ICON, Icons.ACTION_UPDATING_ITEM.getIcon());
|
||||
} else {
|
||||
context.putPresentationProperty(PresentationKey.NAME, name);
|
||||
context.putPresentationProperty(PresentationKey.SMALL_ICON, Icons.ACTION_UPDATE_ARTIFACT);
|
||||
}
|
||||
context.putPresentationProperty(PresentationKey.SHORT_DESCRIPTION, expl);
|
||||
}
|
||||
|
||||
public boolean areBeingDownloaded(List<ItemWrapper> wrappers) {
|
||||
LongList items = PrimitiveUtils.collect(UiItem.GET_ITEM, wrappers);
|
||||
tasks:
|
||||
for (SyncTask task : mySync.getTasks().copyCurrent()) {
|
||||
if (SyncTask.State.isWorking(task.getState().getValue())) {
|
||||
for (LongListIterator i = items.iterator(); i.hasNext();) {
|
||||
if (task.getSpecificActivityForItem(i.nextValue(), null) != SyncTask.SpecificItemActivity.DOWNLOAD)
|
||||
continue tasks;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getPreToggledAndClear() {
|
||||
boolean ret = myPreToggle;
|
||||
myPreToggle = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static class CanDownload extends Condition<ItemWrapper> {
|
||||
public boolean isAccepted(ItemWrapper wrapper) {
|
||||
if(wrapper == null) {
|
||||
return false;
|
||||
}
|
||||
LoadedItem.DBStatus status = wrapper.getDBStatus();
|
||||
return status != LoadedItem.DBStatus.DB_NEW && status != LoadedItem.DBStatus.DB_CONNECTION_NOT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
private static class HasDetails extends Condition<ItemWrapper> {
|
||||
@Override
|
||||
public boolean isAccepted(ItemWrapper value) {
|
||||
ItemDownloadStage stage = ItemDownloadStageKey.retrieveValue(value);
|
||||
return stage == ItemDownloadStage.STALE || stage == ItemDownloadStage.FULL;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.application.tree.GenericNode;
|
||||
import com.almworks.api.engine.Connection;
|
||||
import com.almworks.util.commons.FunctionE;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
|
||||
/**
|
||||
* "Edit Connection" menu action.
|
||||
*/
|
||||
public class EditConnectionAction extends ConnectionAction {
|
||||
public static final EditConnectionAction POPUP = new EditConnectionAction(SELECTED_NODE);
|
||||
public static final EditConnectionAction MAIN = new EditConnectionAction(PARENT_NODE);
|
||||
|
||||
public EditConnectionAction(FunctionE<ActionContext, Connection, CantPerformException> connectionExtractor) {
|
||||
super("&Edit Connection Settings\u2026", connectionExtractor);
|
||||
setDefaultPresentation(PresentationKey.SHORT_DESCRIPTION, "Change connection configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
context.watchRole(GenericNode.NAVIGATION_NODE);
|
||||
final Connection connection = extractConnection(context);
|
||||
if(connection == null || connection.getProvider().isEditingConnection(connection)) {
|
||||
context.setEnabled(EnableState.INVISIBLE);
|
||||
} else {
|
||||
context.setEnabled(EnableState.ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPerform(ActionContext context) throws CantPerformException {
|
||||
final Connection connection = extractConnection(context);
|
||||
if(connection != null) {
|
||||
connection.getProvider().showEditConnectionWizard(connection);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.api.application.tree.GenericNode;
|
||||
import com.almworks.api.application.tree.LazyDistributionExpanderNode;
|
||||
import com.almworks.util.L;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
|
||||
// todo remove
|
||||
public class ExpandLazyDistributionAction extends SimpleAction {
|
||||
public ExpandLazyDistributionAction() {
|
||||
super("Expand Distribution");
|
||||
setDefaultPresentation(PresentationKey.ENABLE, EnableState.INVISIBLE);
|
||||
setDefaultPresentation(PresentationKey.SHORT_DESCRIPTION, L.tooltip("Fill distribution with values"));
|
||||
watchRole(GenericNode.NAVIGATION_NODE);
|
||||
}
|
||||
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
GenericNode node = context.getSourceObject(GenericNode.NAVIGATION_NODE);
|
||||
context.setEnabled(node instanceof LazyDistributionExpanderNode ? EnableState.ENABLED : EnableState.INVISIBLE);
|
||||
}
|
||||
|
||||
protected void doPerform(ActionContext context) throws CantPerformException {
|
||||
GenericNode node = context.getSourceObject(GenericNode.NAVIGATION_NODE);
|
||||
if (node instanceof LazyDistributionExpanderNode)
|
||||
((LazyDistributionExpanderNode) node).expand();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,572 @@
|
|||
package com.almworks.actions;
|
||||
|
||||
import com.almworks.actions.console.actionsource.ActionGroup;
|
||||
import com.almworks.actions.console.actionsource.ConsoleActionsComponent;
|
||||
import com.almworks.actions.distribution.CreateDistribution;
|
||||
import com.almworks.api.application.ExplorerComponent;
|
||||
import com.almworks.api.application.LifeMode;
|
||||
import com.almworks.api.application.qb.FilterNode;
|
||||
import com.almworks.api.application.qb.QueryBuilderComponent;
|
||||
import com.almworks.api.application.tree.*;
|
||||
import com.almworks.api.application.viewer.CommentsController;
|
||||
import com.almworks.api.engine.Connection;
|
||||
import com.almworks.api.engine.Engine;
|
||||
import com.almworks.api.engine.QueryUrlInfo;
|
||||
import com.almworks.api.explorer.TableController;
|
||||
import com.almworks.api.gui.MainMenu;
|
||||
import com.almworks.explorer.ExplorerComponentImpl;
|
||||
import com.almworks.explorer.ShowHideDistributionTableAction;
|
||||
import com.almworks.explorer.ShowHideNavigationAreaAction;
|
||||
import com.almworks.explorer.qbuilder.filter.BinaryCommutative;
|
||||
import com.almworks.explorer.tree.ExcludeDisributionNodeAction;
|
||||
import com.almworks.explorer.tree.NavigationTree;
|
||||
import com.almworks.explorer.tree.OutboxNode;
|
||||
import com.almworks.explorer.tree.TemporaryQueriesNode;
|
||||
import com.almworks.integers.LongList;
|
||||
import com.almworks.sysprop.SystemPropertiesAction;
|
||||
import com.almworks.tags.AddRemoveFavoritesAction;
|
||||
import com.almworks.tags.ImportTagsAction;
|
||||
import com.almworks.tags.NewTagAction;
|
||||
import com.almworks.tags.TagItemsAction;
|
||||
import com.almworks.util.*;
|
||||
import com.almworks.util.commons.Condition;
|
||||
import com.almworks.util.commons.Procedure;
|
||||
import com.almworks.util.commons.Procedure2;
|
||||
import com.almworks.util.components.TreeModelAdapter;
|
||||
import com.almworks.util.components.tabs.TabActions;
|
||||
import com.almworks.util.exec.ThreadGate;
|
||||
import com.almworks.util.files.ExternalBrowser;
|
||||
import com.almworks.util.i18n.Local;
|
||||
import com.almworks.util.images.Icons;
|
||||
import com.almworks.util.model.BasicScalarModel;
|
||||
import com.almworks.util.threads.Bottleneck;
|
||||
import com.almworks.util.threads.Threads;
|
||||
import com.almworks.util.ui.actions.*;
|
||||
import com.almworks.util.ui.swing.Shortcuts;
|
||||
import org.almworks.util.Collections15;
|
||||
import org.picocontainer.Startable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TreeModelEvent;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author : Dyoma
|
||||
*/
|
||||
public class ExplorerActions implements Startable {
|
||||
private final ActionRegistry myRegistry;
|
||||
private final ConsoleActionsComponent myActionConsole;
|
||||
private final Engine myEngine;
|
||||
|
||||
public ExplorerActions(ActionRegistry registry, Engine engine, ConsoleActionsComponent actionConsole) {
|
||||
myRegistry = registry;
|
||||
myActionConsole = actionConsole;
|
||||
myEngine = engine;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
// myRegistry.registerAction(MainMenu.Edit.EDIT_ITEM, new EditPrimaryItemAction()); replaced in JC3
|
||||
myRegistry.registerAction(MainMenu.Edit.VIEW_PROBLEMS, new ShowItemProblemAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.DOWNLOAD, new DownloadItemAction(myEngine));
|
||||
myRegistry.registerAction(MainMenu.Edit.UPLOAD, new UploadItemAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.DISCARD, new DiscardLocalChangesAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.RENAME, new RenameAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.NEW_FOLDER, createCreateFolderAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.ADD_TO_FAVORITES, new AddRemoveFavoritesAction(true));
|
||||
myRegistry.registerAction(MainMenu.Edit.REMOVE_FROM_FAVORITES, new AddRemoveFavoritesAction(false));
|
||||
myRegistry.registerAction(MainMenu.Edit.TAG, new TagItemsAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.NEW_TAG, new NewTagAction(false));
|
||||
myRegistry.registerAction(MainMenu.Edit.COPY_ID_SUMMARY, new CopyIdAndSummaryAction());
|
||||
|
||||
myRegistry.registerAction(MainMenu.Search.NEW_QUERY, createCreateNewQueryAction());
|
||||
myRegistry.registerAction(MainMenu.Search.NEW_DISTRIBUTION, CreateDistribution.createAction());
|
||||
myRegistry.registerAction(MainMenu.Search.EXCLUDE_FROM_DISTRIBUTION, new ExcludeDisributionNodeAction());
|
||||
myRegistry.registerAction(MainMenu.Search.EDIT_QUERY, new EditQueryAction());
|
||||
myRegistry.registerAction(MainMenu.Search.RUN_QUERY, new RunQueryAction());
|
||||
myRegistry.registerAction(MainMenu.Search.RUN_LOCALLY, new ShowCachedResultAction());
|
||||
myRegistry.registerAction(MainMenu.Search.RELOAD_QUERY, new ReloadQueryFromServerAction());
|
||||
myRegistry.registerAction(MainMenu.Search.RUN_QUERY_IN_BROWSER, new OpenQueryInBrowserAction());
|
||||
myRegistry.registerAction(MainMenu.Search.STOP_QUERY, new StopQueryAction());
|
||||
myRegistry.registerAction(MainMenu.Search.CLOSE_CURRENT_TAB, TabActions.createCloseTabAction(
|
||||
ExplorerComponentImpl.MAIN_TABS_MANAGER, "Close Current Ta&b", MainMenu.Search.CLOSE_CURRENT_TAB));
|
||||
myRegistry.registerAction(MainMenu.Search.SELECT_NEXT_TAB, TabActions.createForwardTabAction(
|
||||
ExplorerComponentImpl.MAIN_TABS_MANAGER, "Select Next Tab", MainMenu.Search.SELECT_NEXT_TAB));
|
||||
myRegistry.registerAction(MainMenu.Search.SELECT_PREV_TAB, TabActions.createBackwardTabAction(
|
||||
ExplorerComponentImpl.MAIN_TABS_MANAGER, "Select Previous Tab", MainMenu.Search.SELECT_PREV_TAB));
|
||||
myRegistry.registerAction(MainMenu.Search.OPEN_ITEM_IN_BROWSER, new ViewItemInBrowserAction());
|
||||
|
||||
myRegistry.registerAction(MainMenu.Search.OPEN_ITEM_IN_TAB, new OpenInNewTabAction());
|
||||
myRegistry.registerAction(MainMenu.Search.OPEN_ITEM_IN_FRAME, new OpenInNewFrameAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.SORT_NODES, new SortNodesAction());
|
||||
|
||||
myRegistry.registerAction(MainMenu.File.SHOW_CONNECTION_INFO, ShowConnectionInfo.MAIN);
|
||||
myRegistry.registerAction(MainMenu.File.EDIT_CONNECTION, EditConnectionAction.MAIN);
|
||||
myRegistry.registerAction(MainMenu.File.RETRY_INITIALIZATION, RetryInitializationAction.MAIN);
|
||||
myRegistry.registerAction(MainMenu.File.REMOVE_CONNECTION, RemoveConnectionsAction.create());
|
||||
myRegistry.registerAction(MainMenu.File.UPLOAD_ALL_CHANGES, new UploadLocalChangesAction());
|
||||
|
||||
myRegistry.registerAction(MainMenu.Search.TOP_DUPLICATE_QUERY, new TemporaryDuplicateAction());
|
||||
// myRegistry.registerAction(MainMenu.Search.EXPAND_DISTRIBUTION, new ExpandLazyDistributionAction());
|
||||
// myRegistry.registerAction(MainMenu.Tools.VIEW_NOTE, new ViewNoteAction());
|
||||
|
||||
// myRegistry.registerAction(MainMenu.Edit.DOWNLOAD_DETAILS, new DownloadDetailsAction());
|
||||
// myRegistry.registerAction(MainMenu.Edit.DOWNLOAD_ATTACHMENTS, new DownloadAttachmentsAction());
|
||||
|
||||
myRegistry.registerAction(MainMenu.Windows.FOCUS_NAVIGATION_TREE,
|
||||
new FocusComponentRoleAction(NavigationTree.NAVIGATION_JTREE));
|
||||
myRegistry.registerAction(MainMenu.Windows.FOCUS_TABLE,
|
||||
new FocusComponentRoleAction(TableController.TABLE_COMPONENT));
|
||||
myRegistry.registerAction(MainMenu.Windows.FOCUS_ITEM_VIEWER,
|
||||
new FocusComponentRoleAction(TableController.ARTIFACT_VIWER_COMPONENT));
|
||||
CycleFocusComponentRoleAction cycleFocusAction = new CycleFocusComponentRoleAction(NavigationTree.NAVIGATION_JTREE,
|
||||
TableController.TABLE_COMPONENT, TableController.ARTIFACT_VIWER_COMPONENT);
|
||||
myRegistry.registerAction(MainMenu.Windows.CYCLE_FOCUS, cycleFocusAction);
|
||||
myRegistry.registerAction(MainMenu.Windows.CYCLE_FOCUS_BACK, cycleFocusAction.backwardAction());
|
||||
myRegistry.registerAction(MainMenu.Windows.SHOW_DISTRIBUTION_TABLE, new ShowHideDistributionTableAction());
|
||||
myRegistry.registerAction(MainMenu.Windows.SHOW_NAVIGATION_AREA, ShowHideNavigationAreaAction.INSTANCE);
|
||||
myRegistry.registerAction(TabActions.EXPAND_SHRINK_TABS_ID, ShowHideNavigationAreaAction.INSTANCE);
|
||||
|
||||
myRegistry.registerAction(MainMenu.Tools.REMOVE_BAD_ISSUE, new RemovePrimaryItemAction(myEngine));
|
||||
myRegistry.registerAction(MainMenu.Tools.IMPORT_TAGS, new ImportTagsAction());
|
||||
myRegistry.registerAction(MainMenu.Tools.SYSTEM_PROPERTIES, new SystemPropertiesAction());
|
||||
|
||||
myRegistry.registerAction(MainMenu.Search.FIND, new ShowHighlightPanelAction());
|
||||
|
||||
if (Env.getBoolean(GlobalProperties.INTERNAL_ACTIONS)) {
|
||||
myRegistry.registerAction(MainMenu.Edit.VIEW_CHANGES, new ViewChangesAction());
|
||||
myRegistry.registerAction(MainMenu.Edit.VIEW_ATTRIBUTES, new ViewAttributesAction());
|
||||
myRegistry.registerAction(MainMenu.Tools.VIEW_ITEM_ATTRIBUTES, ViewAttributesAction.createViewItem());
|
||||
myRegistry.registerAction(MainMenu.Edit.VIEW_SHADOWS, new ViewShadowsAction());
|
||||
myRegistry.registerAction(MainMenu.Tools.OPERATION_CONSOLE, ConsoleActionsComponent.OPEN_CONSOLE);
|
||||
}
|
||||
|
||||
registerHideEmptyQueriesActions(myRegistry);
|
||||
|
||||
ToggleLiveModeAction.registerActions(myRegistry);
|
||||
RefreshArtifactsTableAction.registerActions(myRegistry);
|
||||
// CreateItemHelper.registerActions(myRegistry);
|
||||
// MergePrimaryItemAction.registerActions(myRegistry);
|
||||
CommentsController.registerActions(myRegistry);
|
||||
// PrimaryItemEditor.registerActions(myRegistry);
|
||||
// NewArtifactForm.registerActions(myRegistry);
|
||||
// EditorContent.registerActions(myRegistry);
|
||||
registerConsoleActions();
|
||||
}
|
||||
|
||||
private void registerConsoleActions() {
|
||||
// Navigation tree/connection related actions
|
||||
myActionConsole.addGroup(new ActionGroup.InContext("Connection", GenericNode.NAVIGATION_NODE,
|
||||
MainMenu.File.EDIT_CONNECTION, MainMenu.File.SHOW_CONNECTION_INFO, MainMenu.File.RETRY_INITIALIZATION, MainMenu.File.REMOVE_CONNECTION,
|
||||
MainMenu.File.DOWNLOAD_CHANGES_QUICK_POPUP, MainMenu.File.RELOAD_CONFIGURATION_POPUP));
|
||||
}
|
||||
|
||||
private void registerHideEmptyQueriesActions(ActionRegistry registry) {
|
||||
registry.registerAction(MainMenu.Search.HIDE_EMPTY_QUERIES_ON, new HideEmptyQueriesChooserAction("Hide",
|
||||
"Hide sub-queries that would show zero " + Terms.ref_artifacts, Boolean.TRUE));
|
||||
registry.registerAction(MainMenu.Search.HIDE_EMPTY_QUERIES_OFF, new HideEmptyQueriesChooserAction("Show",
|
||||
"Do not hide sub-queries that would show zero " + Terms.ref_artifacts, Boolean.FALSE));
|
||||
}
|
||||
|
||||
private CreateChildNodeAction createCreateNewQueryAction() {
|
||||
CreateChildNodeAction action =
|
||||
CreateChildNodeAction.create(Icons.ACTION_CREATE_NEW_QUERY, TreeNodeFactory.NodeType.QUERY);
|
||||
action.setDefaultPresentation(PresentationKey.NAME, L.actionName("New &" + Terms.Query));
|
||||
action.setDefaultPresentation(PresentationKey.SHORT_DESCRIPTION, L.tooltip("Create a new " + Terms.query));
|
||||
return action;
|
||||
}
|
||||
|
||||
private CreateChildNodeAction createCreateFolderAction() {
|
||||
CreateChildNodeAction action = CreateChildNodeAction.create(TreeNodeFactory.NodeType.FOLDER);
|
||||
action.setDefaultPresentation(PresentationKey.NAME, L.actionName("&New " + Terms.Folder));
|
||||
action.setDefaultPresentation(PresentationKey.SHORT_DESCRIPTION, L.tooltip("Create a new " + Terms.folder));
|
||||
return action;
|
||||
}
|
||||
|
||||
public static <T extends GenericNode> T getSingleNavigationNode(ActionContext context, DataRole<T> role)
|
||||
throws CantPerformException
|
||||
{
|
||||
try {
|
||||
return context.getSourceObject(role);
|
||||
} catch (CantPerformException e) {
|
||||
GenericNode node = context.getSourceObject(GenericNode.NAVIGATION_NODE);
|
||||
if (role.matches(node))
|
||||
return (T) node;
|
||||
throw new CantPerformException("No role: " + role + " object: " + node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void stop() {
|
||||
}
|
||||
|
||||
private static class HideEmptyQueriesChooserAction extends SimpleAction {
|
||||
private Boolean myValue;
|
||||
|
||||
public HideEmptyQueriesChooserAction(String name, String description, Boolean value) {
|
||||
super(name);
|
||||
setDefaultPresentation(PresentationKey.ENABLE, EnableState.INVISIBLE);
|
||||
setDefaultPresentation(PresentationKey.SHORT_DESCRIPTION, Local.parse(description));
|
||||
watchRole(GenericNode.NAVIGATION_NODE);
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
protected void customUpdate(UpdateContext context) throws CantPerformException {
|
||||
final GenericNode node = context.getSourceObject(GenericNode.NAVIGATION_NODE);
|
||||
context.putPresentationProperty(PresentationKey.TOGGLED_ON, Boolean.valueOf(node.getHideEmptyChildren()).equals(myValue));
|
||||
context.putPresentationProperty(PresentationKey.ENABLE,
|
||||
node.canHideEmptyChildren() ? EnableState.ENABLED : EnableState.INVISIBLE);
|
||||
}
|
||||