Initial commit
Some checks failed
Gradle Build / build (push) Has been cancelled

This commit is contained in:
CaiXiang
2024-11-30 18:36:13 +08:00
commit aa56926258
2134 changed files with 232943 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
apply from: "${rootDir}/gradle/java-project.gradle"
apply from: "${rootDir}/gradle/java-codequality.gradle"
apply from: "${rootDir}/gradle/guice-application.gradle"
apply from: "${rootDir}/gradle/publishing-java.gradle"
if (!hasProperty('mainClass')) {
ext.mainClass = 'org.opentcs.operationsdesk.RunOperationsDesk'
}
application.mainClass = ext.mainClass
ext.collectableDistDir = new File(buildDir, 'install')
dependencies {
api project(':opentcs-common')
api project(':opentcs-impl-configuration-gestalt')
api project(':opentcs-plantoverview-common')
api project(':opentcs-plantoverview-panel-loadgenerator')
api project(':opentcs-plantoverview-panel-resourceallocation')
api project(':opentcs-plantoverview-themes-default')
runtimeOnly group: 'org.slf4j', name: 'slf4j-jdk14', version: '2.0.16'
}
compileJava {
options.compilerArgs << "-Xlint:-rawtypes"
}
distributions {
main {
contents {
from "${sourceSets.main.resources.srcDirs[0]}/org/opentcs/operationsdesk/distribution"
}
}
}
// For now, we're using hand-crafted start scripts, so disable the application
// plugin's start script generation.
startScripts.enabled = false
distTar.enabled = false
task release {
dependsOn build
dependsOn installDist
}
run {
systemProperties(['java.util.logging.config.file':'./config/logging.config',\
'sun.java2d.d3d':'false',\
'opentcs.base':'.',\
'opentcs.home':'.',\
'opentcs.configuration.reload.interval':'10000',\
'opentcs.configuration.provider':'gestalt'])
jvmArgs('-XX:-OmitStackTraceInFastThrow',\
'-splash:bin/splash-image.gif')
}

View File

@@ -0,0 +1,40 @@
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapAnnotationArgs=WRAP_IF_LONG
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineMethodParams=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapAfterDotInChainedMethodCalls=false
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineDisjunctiveCatchTypes=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineFor=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineImplements=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapFor=WRAP_IF_LONG
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.sortMembersByVisibility=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.visibilityOrder=PUBLIC;PROTECTED;DEFAULT;PRIVATE
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeFinallyOnNewLine=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapMethodParams=WRAP_IF_LONG
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enable-indent=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineArrayInit=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineCallArgs=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapDisjunctiveCatchTypes=WRAP_IF_LONG
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.keepGettersAndSettersTogether=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapExtendsImplementsList=WRAP_ALWAYS
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapThrowsKeyword=WRAP_ALWAYS
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapExtendsImplementsKeyword=WRAP_ALWAYS
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classMembersOrder=STATIC FIELD;FIELD;STATIC_INIT;CONSTRUCTOR;INSTANCE_INIT;STATIC METHOD;METHOD;STATIC CLASS;CLASS
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapEnumConstants=WRAP_ALWAYS
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapCommentText=false
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapThrowsList=WRAP_IF_LONG
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.wrapAssert=WRAP_IF_LONG
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder=*
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.continuationIndentSize=4
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeElseOnNewLine=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeCatchOnNewLine=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineAnnotationArgs=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineTryResources=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.preserveNewLinesInComments=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineParenthesized=true
netbeans.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineThrows=true
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=2
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=2
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=2
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=100
netbeans.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=true
netbeans.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,2 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: CC-BY-4.0

View File

@@ -0,0 +1,66 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: CC-BY-4.0
############################################################
# Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################
############################################################
# Global properties
############################################################
# "handlers" specifies a comma separated list of log Handler
# classes. These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
#handlers= java.util.logging.ConsoleHandler
# To also add the FileHandler, use the following line instead.
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers. For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = ./log/opentcs-operationsdesk.%g.log
java.util.logging.FileHandler.limit = 500000
java.util.logging.FileHandler.count = 10
#java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.formatter = org.opentcs.util.logging.SingleLineFormatter
java.util.logging.FileHandler.append = true
java.util.logging.FileHandler.level = FINE
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
#java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.formatter = org.opentcs.util.logging.SingleLineFormatter
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
#com.xyz.foo.level = SEVERE
# Logging configuration for single classes. Remember that you might also have to
# adjust handler levels!
#org.opentcs.guing.*.level = FINE
#org.opentcs.access.rmi.ProxyInvocationHandler.level = FINE

View File

@@ -0,0 +1,2 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: CC-BY-4.0

View File

View File

@@ -0,0 +1,38 @@
@echo off
rem SPDX-FileCopyrightText: The openTCS Authors
rem SPDX-License-Identifier: MIT
rem
rem Start the openTCS Operations Desk application.
rem
rem Set window title
title Operations Desk (openTCS)
rem Don't export variables to the parent shell
setlocal
rem Set base directory names.
set OPENTCS_BASE=.
set OPENTCS_HOME=.
set OPENTCS_CONFIGDIR=%OPENTCS_HOME%\config
set OPENTCS_LIBDIR=%OPENTCS_BASE%\lib
rem Set the class path
set OPENTCS_CP=%OPENTCS_LIBDIR%\*;
set OPENTCS_CP=%OPENTCS_CP%;%OPENTCS_LIBDIR%\openTCS-extensions\*;
rem XXX Be a bit more clever to find out the name of the JVM runtime.
set JAVA=javaw
rem Start plant overview
start /b %JAVA% -enableassertions ^
-Dopentcs.base="%OPENTCS_BASE%" ^
-Dopentcs.home="%OPENTCS_HOME%" ^
-Dopentcs.configuration.provider=gestalt ^
-Dopentcs.configuration.reload.interval=10000 ^
-Djava.util.logging.config.file="%OPENTCS_CONFIGDIR%\logging.config" ^
-Dsun.java2d.d3d=false ^
-XX:-OmitStackTraceInFastThrow ^
-classpath "%OPENTCS_CP%" ^
-splash:bin/splash-image.gif ^
org.opentcs.operationsdesk.RunOperationsDesk

View File

@@ -0,0 +1,35 @@
#!/bin/sh
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: MIT
#
# Start the openTCS Operations Desk application.
#
# Set base directory names.
export OPENTCS_BASE=.
export OPENTCS_HOME=.
export OPENTCS_CONFIGDIR="${OPENTCS_HOME}/config"
export OPENTCS_LIBDIR="${OPENTCS_BASE}/lib"
# Set the class path
export OPENTCS_CP="${OPENTCS_LIBDIR}/*"
export OPENTCS_CP="${OPENTCS_CP}:${OPENTCS_LIBDIR}/openTCS-extensions/*"
if [ -n "${OPENTCS_JAVAVM}" ]; then
export JAVA="${OPENTCS_JAVAVM}"
else
# XXX Be a bit more clever to find out the name of the JVM runtime.
export JAVA="java"
fi
# Start plant overview
${JAVA} -enableassertions \
-Dopentcs.base="${OPENTCS_BASE}" \
-Dopentcs.home="${OPENTCS_HOME}" \
-Dopentcs.configuration.provider=gestalt \
-Dopentcs.configuration.reload.interval=10000 \
-Djava.util.logging.config.file=${OPENTCS_CONFIGDIR}/logging.config \
-XX:-OmitStackTraceInFastThrow \
-classpath "${OPENTCS_CP}" \
-splash:bin/splash-image.gif \
org.opentcs.operationsdesk.RunOperationsDesk

View File

@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
/**
* Configures/binds the default importers and exporters of the openTCS plant overview.
*/
public class DefaultImportersExportersModule
extends
PlantOverviewInjectionModule {
/**
* Creates a new instance.
*/
public DefaultImportersExportersModule() {
}
@Override
protected void configure() {
plantModelImporterBinder();
plantModelExporterBinder();
}
}

View File

@@ -0,0 +1,166 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk;
import com.google.inject.TypeLiteral;
import jakarta.inject.Singleton;
import java.io.File;
import java.util.List;
import java.util.Locale;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.opentcs.access.KernelServicePortal;
import org.opentcs.access.SslParameterSet;
import org.opentcs.access.rmi.KernelServicePortalBuilder;
import org.opentcs.access.rmi.factories.NullSocketFactoryProvider;
import org.opentcs.access.rmi.factories.SecureSocketFactoryProvider;
import org.opentcs.access.rmi.factories.SocketFactoryProvider;
import org.opentcs.common.GuestUserCredentials;
import org.opentcs.components.plantoverview.LocationTheme;
import org.opentcs.components.plantoverview.VehicleTheme;
import org.opentcs.customizations.ApplicationHome;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
import org.opentcs.drivers.LowLevelCommunicationEvent;
import org.opentcs.guing.common.exchange.ApplicationPortalProviderConfiguration;
import org.opentcs.guing.common.exchange.SslConfiguration;
import org.opentcs.operationsdesk.application.ApplicationInjectionModule;
import org.opentcs.operationsdesk.components.ComponentsInjectionModule;
import org.opentcs.operationsdesk.exchange.ExchangeInjectionModule;
import org.opentcs.operationsdesk.model.ModelInjectionModule;
import org.opentcs.operationsdesk.notifications.NotificationInjectionModule;
import org.opentcs.operationsdesk.peripherals.jobs.PeripheralJobInjectionModule;
import org.opentcs.operationsdesk.persistence.DefaultPersistenceInjectionModule;
import org.opentcs.operationsdesk.transport.TransportInjectionModule;
import org.opentcs.operationsdesk.util.OperationsDeskConfiguration;
import org.opentcs.operationsdesk.util.UtilInjectionModule;
import org.opentcs.util.ClassMatcher;
import org.opentcs.util.gui.dialog.ConnectionParamSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Guice module for the openTCS plant overview application.
*/
public class DefaultPlantOverviewInjectionModule
extends
PlantOverviewInjectionModule {
/**
* This class's logger.
*/
private static final Logger LOG
= LoggerFactory.getLogger(DefaultPlantOverviewInjectionModule.class);
/**
* Creates a new instance.
*/
public DefaultPlantOverviewInjectionModule() {
}
@Override
protected void configure() {
File applicationHome = new File(System.getProperty("opentcs.home", "."));
bind(File.class)
.annotatedWith(ApplicationHome.class)
.toInstance(applicationHome);
configurePlantOverviewDependencies();
install(new ApplicationInjectionModule());
install(new ComponentsInjectionModule());
install(new ExchangeInjectionModule());
install(new ModelInjectionModule());
install(new DefaultPersistenceInjectionModule());
install(new TransportInjectionModule());
install(new NotificationInjectionModule());
install(new PeripheralJobInjectionModule());
install(new UtilInjectionModule());
// Ensure there is at least an empty binder for pluggable panels.
pluggablePanelFactoryBinder();
// Ensure there is at least an empty binder for history entry formatters.
objectHistoryEntryFormatterBinder();
}
private void configurePlantOverviewDependencies() {
OperationsDeskConfiguration configuration
= getConfigBindingProvider().get(
OperationsDeskConfiguration.PREFIX,
OperationsDeskConfiguration.class
);
bind(ApplicationPortalProviderConfiguration.class)
.toInstance(configuration);
bind(OperationsDeskConfiguration.class)
.toInstance(configuration);
configurePlantOverview(configuration);
configureThemes(configuration);
configureSocketConnections();
bind(new TypeLiteral<List<ConnectionParamSet>>() {
})
.toInstance(configuration.connectionBookmarks());
}
private void configureSocketConnections() {
SslConfiguration sslConfiguration = getConfigBindingProvider().get(
SslConfiguration.PREFIX,
SslConfiguration.class
);
//Create the data object for the ssl configuration
SslParameterSet sslParamSet = new SslParameterSet(
SslParameterSet.DEFAULT_KEYSTORE_TYPE,
null,
null,
new File(sslConfiguration.truststoreFile()),
sslConfiguration.truststorePassword()
);
bind(SslParameterSet.class).toInstance(sslParamSet);
SocketFactoryProvider socketFactoryProvider;
if (sslConfiguration.enable()) {
socketFactoryProvider = new SecureSocketFactoryProvider(sslParamSet);
}
else {
LOG.warn("SSL encryption disabled, connections will not be secured!");
socketFactoryProvider = new NullSocketFactoryProvider();
}
//Bind socket provider to the kernel portal
bind(KernelServicePortal.class)
.toInstance(
new KernelServicePortalBuilder(
GuestUserCredentials.USER,
GuestUserCredentials.PASSWORD
)
.setSocketFactoryProvider(socketFactoryProvider)
.setEventFilter(new ClassMatcher(LowLevelCommunicationEvent.class).negate())
.build()
);
}
private void configureThemes(OperationsDeskConfiguration configuration) {
bind(LocationTheme.class)
.to(configuration.locationThemeClass())
.in(Singleton.class);
bind(VehicleTheme.class)
.to(configuration.vehicleThemeClass())
.in(Singleton.class);
}
private void configurePlantOverview(
OperationsDeskConfiguration configuration
) {
Locale.setDefault(Locale.forLanguageTag(configuration.locale()));
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException ex) {
LOG.warn("Could not set look-and-feel", ex);
}
// Show tooltips for 30 seconds (Default: 4 sec)
ToolTipManager.sharedInstance().setDismissDelay(30 * 1000);
}
}

View File

@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk;
import java.util.HashSet;
import java.util.Set;
import org.opentcs.common.LoopbackAdapterConstants;
import org.opentcs.components.kernel.Dispatcher;
import org.opentcs.components.kernel.Router;
import org.opentcs.components.kernel.Scheduler;
import org.opentcs.components.plantoverview.PropertySuggestions;
/**
* The default property suggestions of the baseline plant overview.
*/
public class DefaultPropertySuggestions
implements
PropertySuggestions {
private final Set<String> keySuggestions = new HashSet<>();
private final Set<String> valueSuggestions = new HashSet<>();
/**
* Creates a new instance.
*/
public DefaultPropertySuggestions() {
keySuggestions.add(Scheduler.PROPKEY_BLOCK_ENTRY_DIRECTION);
keySuggestions.add(Router.PROPKEY_ROUTING_GROUP);
keySuggestions.add(Dispatcher.PROPKEY_PARKING_POSITION_PRIORITY);
keySuggestions.add(Dispatcher.PROPKEY_ASSIGNED_PARKING_POSITION);
keySuggestions.add(Dispatcher.PROPKEY_PREFERRED_PARKING_POSITION);
keySuggestions.add(Dispatcher.PROPKEY_ASSIGNED_RECHARGE_LOCATION);
keySuggestions.add(Dispatcher.PROPKEY_PREFERRED_RECHARGE_LOCATION);
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_INITIAL_POSITION);
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_OPERATING_TIME);
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_LOAD_OPERATION);
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_UNLOAD_OPERATION);
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_ACCELERATION);
keySuggestions.add(LoopbackAdapterConstants.PROPKEY_DECELERATION);
}
@Override
public Set<String> getKeySuggestions() {
return keySuggestions;
}
@Override
public Set<String> getValueSuggestions() {
return valueSuggestions;
}
}

View File

@@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk;
import jakarta.inject.Singleton;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
/**
* This module configures the multibinder used to suggest key value properties in the editor.
*/
public class PropertySuggestionsModule
extends
PlantOverviewInjectionModule {
/**
* Creates a new instance.
*/
public PropertySuggestionsModule() {
}
@Override
protected void configure() {
propertySuggestionsBinder().addBinding()
.to(DefaultPropertySuggestions.class)
.in(Singleton.class);
}
}

View File

@@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.util.Modules;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import org.opentcs.configuration.ConfigurationBindingProvider;
import org.opentcs.configuration.gestalt.GestaltConfigurationBindingProvider;
import org.opentcs.customizations.ConfigurableInjectionModule;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
import org.opentcs.guing.common.util.CompatibilityChecker;
import org.opentcs.operationsdesk.application.PlantOverviewStarter;
import org.opentcs.util.Environment;
import org.opentcs.util.logging.UncaughtExceptionLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The plant overview process's default entry point.
*/
public class RunOperationsDesk {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(RunOperationsDesk.class);
/**
* Prevents external instantiation.
*/
private RunOperationsDesk() {
}
/**
* The plant overview client's main entry point.
*
* @param args the command line arguments
*/
public static void main(final String[] args) {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger(false));
Environment.logSystemInfo();
ensureVersionCompatibility();
Injector injector = Guice.createInjector(customConfigurationModule());
injector.getInstance(PlantOverviewStarter.class).startPlantOverview();
}
private static void ensureVersionCompatibility() {
String version = System.getProperty("java.version");
if (!CompatibilityChecker.versionCompatibleWithDockingFrames(version)) {
LOG.error("Version incompatible with Docking Frames: '{}'", version);
CompatibilityChecker.showVersionIncompatibleWithDockingFramesMessage();
System.exit(1);
}
}
/**
* Builds and returns a Guice module containing the custom configuration for the plant overview
* application, including additions and overrides by the user.
*
* @return The custom configuration module.
*/
private static Module customConfigurationModule() {
ConfigurationBindingProvider bindingProvider = configurationBindingProvider();
ConfigurableInjectionModule plantOverviewInjectionModule
= new DefaultPlantOverviewInjectionModule();
plantOverviewInjectionModule.setConfigBindingProvider(bindingProvider);
return Modules.override(plantOverviewInjectionModule)
.with(findRegisteredModules(bindingProvider));
}
/**
* Finds and returns all Guice modules registered via ServiceLoader.
*
* @return The registered/found modules.
*/
private static List<PlantOverviewInjectionModule> findRegisteredModules(
ConfigurationBindingProvider bindingProvider
) {
List<PlantOverviewInjectionModule> registeredModules = new ArrayList<>();
for (PlantOverviewInjectionModule module : ServiceLoader.load(
PlantOverviewInjectionModule.class
)) {
LOG.info(
"Integrating injection module {} (source: {})",
module.getClass().getName(),
module.getClass().getProtectionDomain().getCodeSource()
);
module.setConfigBindingProvider(bindingProvider);
registeredModules.add(module);
}
return registeredModules;
}
private static ConfigurationBindingProvider configurationBindingProvider() {
String chosenProvider = System.getProperty("opentcs.configuration.provider", "gestalt");
switch (chosenProvider) {
case "gestalt":
default:
LOG.info("Using gestalt as the configuration provider.");
return gestaltConfigurationBindingProvider();
}
}
private static ConfigurationBindingProvider gestaltConfigurationBindingProvider() {
return new GestaltConfigurationBindingProvider(
Paths.get(
System.getProperty("opentcs.base", "."),
"config",
"opentcs-operationsdesk-defaults-baseline.properties"
)
.toAbsolutePath(),
Paths.get(
System.getProperty("opentcs.base", "."),
"config",
"opentcs-operationsdesk-defaults-custom.properties"
)
.toAbsolutePath(),
Paths.get(
System.getProperty("opentcs.home", "."),
"config",
"opentcs-operationsdesk.properties"
)
.toAbsolutePath()
);
}
}

View File

@@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application;
import com.google.inject.AbstractModule;
import jakarta.inject.Singleton;
import java.awt.Component;
import javax.swing.JFrame;
import org.jhotdraw.app.Application;
import org.opentcs.common.KernelClientApplication;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.common.application.ApplicationState;
import org.opentcs.guing.common.application.ComponentsManager;
import org.opentcs.guing.common.application.GuiManager;
import org.opentcs.guing.common.application.PluginPanelManager;
import org.opentcs.guing.common.application.ProgressIndicator;
import org.opentcs.guing.common.application.SplashFrame;
import org.opentcs.guing.common.application.StatusPanel;
import org.opentcs.guing.common.application.ViewManager;
import org.opentcs.operationsdesk.application.action.ActionInjectionModule;
import org.opentcs.operationsdesk.application.menus.MenusInjectionModule;
import org.opentcs.operationsdesk.application.toolbar.ToolBarInjectionModule;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.action.edit.UndoRedoManager;
import org.opentcs.thirdparty.operationsdesk.jhotdraw.application.OpenTCSSDIApplication;
/**
* An injection module for this package.
*/
public class ApplicationInjectionModule
extends
AbstractModule {
/**
* The application's main frame.
*/
private final JFrame applicationFrame = new JFrame();
/**
* Creates a new instance.
*/
public ApplicationInjectionModule() {
}
@Override
protected void configure() {
install(new ActionInjectionModule());
install(new MenusInjectionModule());
install(new ToolBarInjectionModule());
bind(ApplicationState.class).in(Singleton.class);
bind(UndoRedoManager.class).in(Singleton.class);
bind(ProgressIndicator.class)
.to(SplashFrame.class)
.in(Singleton.class);
bind(StatusPanel.class).in(Singleton.class);
bind(JFrame.class)
.annotatedWith(ApplicationFrame.class)
.toInstance(applicationFrame);
bind(Component.class)
.annotatedWith(ApplicationFrame.class)
.toInstance(applicationFrame);
bind(ViewManagerOperating.class)
.in(Singleton.class);
bind(ViewManager.class).to(ViewManagerOperating.class);
bind(Application.class)
.to(OpenTCSSDIApplication.class)
.in(Singleton.class);
bind(OpenTCSView.class).in(Singleton.class);
bind(GuiManager.class).to(OpenTCSView.class);
bind(ComponentsManager.class).to(OpenTCSView.class);
bind(PluginPanelManager.class).to(OpenTCSView.class);
bind(KernelClientApplication.class)
.to(OperationsDeskApplication.class)
.in(Singleton.class);
}
}

View File

@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
/**
* An injection module for this package.
*/
public class ActionInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public ActionInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(ActionFactory.class));
bind(ViewActionMap.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
/**
*/
public class MenusInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public MenusInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(MenuFactory.class));
}
}

View File

@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.toolbar;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
import org.jhotdraw.draw.tool.DragTracker;
import org.jhotdraw.draw.tool.SelectAreaTracker;
import org.opentcs.operationsdesk.application.action.ToolBarManager;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.toolbar.OpenTCSDragTracker;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.toolbar.OpenTCSSelectAreaTracker;
/**
*/
public class ToolBarInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public ToolBarInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(SelectionToolFactory.class));
bind(ToolBarManager.class).in(Singleton.class);
bind(SelectAreaTracker.class).to(OpenTCSSelectAreaTracker.class);
bind(DragTracker.class).to(OpenTCSDragTracker.class);
}
}

View File

@@ -0,0 +1,116 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components;
import com.google.inject.AbstractModule;
import com.google.inject.PrivateModule;
import jakarta.inject.Singleton;
import java.awt.event.MouseListener;
import org.opentcs.guing.common.components.tree.AbstractTreeViewPanel;
import org.opentcs.guing.common.components.tree.BlockMouseListener;
import org.opentcs.guing.common.components.tree.BlocksTreeViewManager;
import org.opentcs.guing.common.components.tree.BlocksTreeViewPanel;
import org.opentcs.guing.common.components.tree.ComponentsTreeViewManager;
import org.opentcs.guing.common.components.tree.ComponentsTreeViewPanel;
import org.opentcs.guing.common.components.tree.TreeMouseAdapter;
import org.opentcs.guing.common.components.tree.TreeView;
import org.opentcs.operationsdesk.components.dialogs.DialogsInjectionModule;
import org.opentcs.operationsdesk.components.dockable.DockableInjectionModule;
import org.opentcs.operationsdesk.components.drawing.DrawingInjectionModule;
import org.opentcs.operationsdesk.components.layer.LayersInjectionModule;
import org.opentcs.operationsdesk.components.properties.PropertiesInjectionModule;
import org.opentcs.operationsdesk.components.tree.elements.TreeElementsInjectionModule;
/**
* A Guice module for this package.
*/
public class ComponentsInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public ComponentsInjectionModule() {
}
@Override
protected void configure() {
install(new DialogsInjectionModule());
install(new DockableInjectionModule());
install(new DrawingInjectionModule());
install(new PropertiesInjectionModule());
install(new TreeElementsInjectionModule());
install(new ComponentsTreeViewModule());
install(new BlocksTreeViewModule());
install(new LayersInjectionModule());
}
private static class ComponentsTreeViewModule
extends
PrivateModule {
ComponentsTreeViewModule() {
}
@Override
protected void configure() {
// Within this (private) module, there should only be a single tree panel.
bind(ComponentsTreeViewPanel.class)
.in(Singleton.class);
// Bind the tree panel annotated with the given annotation to our single
// instance and expose only this annotated version.
bind(AbstractTreeViewPanel.class)
.to(ComponentsTreeViewPanel.class);
expose(ComponentsTreeViewPanel.class);
// Bind TreeView to the single tree panel, too.
bind(TreeView.class)
.to(ComponentsTreeViewPanel.class);
// Bind and expose a single manager for the single tree view/panel.
bind(ComponentsTreeViewManager.class)
.in(Singleton.class);
expose(ComponentsTreeViewManager.class);
bind(MouseListener.class)
.to(TreeMouseAdapter.class);
}
}
private static class BlocksTreeViewModule
extends
PrivateModule {
BlocksTreeViewModule() {
}
@Override
protected void configure() {
// Within this (private) module, there should only be a single tree panel.
bind(BlocksTreeViewPanel.class)
.in(Singleton.class);
// Bind the tree panel annotated with the given annotation to our single
// instance and expose only this annotated version.
bind(AbstractTreeViewPanel.class)
.to(BlocksTreeViewPanel.class);
expose(BlocksTreeViewPanel.class);
// Bind TreeView to the single tree panel, too.
bind(TreeView.class)
.to(BlocksTreeViewPanel.class);
// Bind and expose a single manager for the single tree view/panel.
bind(BlocksTreeViewManager.class)
.in(Singleton.class);
expose(BlocksTreeViewManager.class);
bind(MouseListener.class)
.to(BlockMouseListener.class);
}
}
}

View File

@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
/**
* A Guice module for this package.
*/
public class DialogsInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public DialogsInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(SingleVehicleViewFactory.class));
install(new FactoryModuleBuilder().build(FindVehiclePanelFactory.class));
bind(VehiclesPanel.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dockable;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
import org.opentcs.guing.common.components.dockable.DockableHandlerFactory;
import org.opentcs.guing.common.components.dockable.DockingManager;
/**
* A Guice module for this package.
*/
public class DockableInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public DockableInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(DockableHandlerFactory.class));
bind(DockingManagerOperating.class).in(Singleton.class);
bind(DockingManager.class).to(DockingManagerOperating.class);
}
}

View File

@@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
import org.jhotdraw.draw.DrawingEditor;
import org.opentcs.guing.common.components.drawing.DrawingOptions;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.guing.common.components.drawing.figures.ToolTipTextGenerator;
import org.opentcs.guing.common.util.CourseObjectFactory;
import org.opentcs.operationsdesk.components.drawing.figures.ToolTipTextGeneratorOperationsDesk;
import org.opentcs.operationsdesk.components.drawing.figures.VehicleFigureFactory;
import org.opentcs.operationsdesk.util.VehicleCourseObjectFactory;
import org.opentcs.thirdparty.operationsdesk.components.drawing.OpenTCSDrawingViewOperating;
/**
* A Guice module for this package.
*/
public class DrawingInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public DrawingInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(VehicleFigureFactory.class));
bind(CourseObjectFactory.class).to(VehicleCourseObjectFactory.class);
bind(OpenTCSDrawingEditorOperating.class).in(Singleton.class);
bind(OpenTCSDrawingEditor.class).to(OpenTCSDrawingEditorOperating.class);
bind(DrawingEditor.class).to(OpenTCSDrawingEditorOperating.class);
bind(OpenTCSDrawingView.class).to(OpenTCSDrawingViewOperating.class);
bind(DrawingOptions.class).in(Singleton.class);
bind(ToolTipTextGeneratorOperationsDesk.class).in(Singleton.class);
bind(ToolTipTextGenerator.class).to(ToolTipTextGeneratorOperationsDesk.class);
}
}

View File

@@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.layer;
import jakarta.inject.Singleton;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
import org.opentcs.guing.common.components.layer.DefaultLayerManager;
import org.opentcs.guing.common.components.layer.LayerEditor;
import org.opentcs.guing.common.components.layer.LayerGroupEditor;
import org.opentcs.guing.common.components.layer.LayerGroupManager;
import org.opentcs.guing.common.components.layer.LayerManager;
/**
* A Guice module for this package.
*/
public class LayersInjectionModule
extends
PlantOverviewInjectionModule {
/**
* Creates a new instance.
*/
public LayersInjectionModule() {
}
@Override
protected void configure() {
bind(DefaultLayerManager.class).in(Singleton.class);
bind(LayerManager.class).to(DefaultLayerManager.class);
bind(LayerEditor.class).to(DefaultLayerManager.class);
bind(LayersPanel.class).in(Singleton.class);
bind(LayerGroupManager.class).to(DefaultLayerManager.class);
bind(LayerGroupEditor.class).to(DefaultLayerManager.class);
bind(LayerGroupsPanel.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,90 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.properties;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.multibindings.MapBinder;
import jakarta.inject.Singleton;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
import org.opentcs.guing.base.components.properties.type.AbstractComplexProperty;
import org.opentcs.guing.base.components.properties.type.EnergyLevelThresholdSetProperty;
import org.opentcs.guing.base.components.properties.type.KeyValueProperty;
import org.opentcs.guing.base.components.properties.type.KeyValueSetProperty;
import org.opentcs.guing.base.components.properties.type.LinkActionsProperty;
import org.opentcs.guing.base.components.properties.type.LocationTypeActionsProperty;
import org.opentcs.guing.base.components.properties.type.OrderTypesProperty;
import org.opentcs.guing.base.components.properties.type.ResourceProperty;
import org.opentcs.guing.base.components.properties.type.SymbolProperty;
import org.opentcs.guing.common.components.dialogs.DetailsDialogContent;
import org.opentcs.guing.common.components.properties.PropertiesComponentsFactory;
import org.opentcs.guing.common.components.properties.SelectionPropertiesComponent;
import org.opentcs.guing.common.components.properties.panel.EnergyLevelThresholdSetPropertyEditorPanel;
import org.opentcs.guing.common.components.properties.panel.KeyValuePropertyEditorPanel;
import org.opentcs.guing.common.components.properties.panel.KeyValueSetPropertyViewerEditorPanel;
import org.opentcs.guing.common.components.properties.panel.LinkActionsEditorPanel;
import org.opentcs.guing.common.components.properties.panel.LocationTypeActionsEditorPanel;
import org.opentcs.guing.common.components.properties.panel.OrderTypesPropertyEditorPanel;
import org.opentcs.guing.common.components.properties.panel.PropertiesPanelFactory;
import org.opentcs.guing.common.components.properties.panel.ResourcePropertyViewerEditorPanel;
import org.opentcs.guing.common.components.properties.panel.SymbolPropertyEditorPanel;
import org.opentcs.guing.common.components.properties.table.CellEditorFactory;
/**
* A Guice module for this package.
*/
public class PropertiesInjectionModule
extends
PlantOverviewInjectionModule {
/**
* Creates a new instance.
*/
public PropertiesInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(PropertiesPanelFactory.class));
install(new FactoryModuleBuilder().build(CellEditorFactory.class));
install(new FactoryModuleBuilder().build(PropertiesComponentsFactory.class));
MapBinder<Class<? extends AbstractComplexProperty>, DetailsDialogContent> dialogContentMapBinder
= MapBinder.newMapBinder(
binder(),
new TypeLiteral<Class<? extends AbstractComplexProperty>>() {
},
new TypeLiteral<DetailsDialogContent>() {
}
);
dialogContentMapBinder
.addBinding(KeyValueProperty.class)
.to(KeyValuePropertyEditorPanel.class);
dialogContentMapBinder
.addBinding(KeyValueSetProperty.class)
.to(KeyValueSetPropertyViewerEditorPanel.class);
dialogContentMapBinder
.addBinding(LocationTypeActionsProperty.class)
.to(LocationTypeActionsEditorPanel.class);
dialogContentMapBinder
.addBinding(LinkActionsProperty.class)
.to(LinkActionsEditorPanel.class);
dialogContentMapBinder
.addBinding(SymbolProperty.class)
.to(SymbolPropertyEditorPanel.class);
dialogContentMapBinder
.addBinding(OrderTypesProperty.class)
.to(OrderTypesPropertyEditorPanel.class);
dialogContentMapBinder
.addBinding(EnergyLevelThresholdSetProperty.class)
.to(EnergyLevelThresholdSetPropertyEditorPanel.class);
dialogContentMapBinder
.addBinding(ResourceProperty.class)
.to(ResourcePropertyViewerEditorPanel.class);
bind(SelectionPropertiesComponent.class)
.in(Singleton.class);
}
}

View File

@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.tree.elements;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.opentcs.guing.common.components.tree.elements.UserObjectFactory;
import org.opentcs.guing.common.components.tree.elements.VehicleUserObject;
/**
* A Guice module for this package.
*/
public class TreeElementsInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public TreeElementsInjectionModule() {
}
@Override
protected void configure() {
install(
new FactoryModuleBuilder()
.implement(VehicleUserObject.class, VehicleUserObjectOperating.class)
.build(UserObjectFactory.class)
);
}
}

View File

@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.exchange;
import com.google.inject.AbstractModule;
import jakarta.inject.Singleton;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.common.DefaultPortalManager;
import org.opentcs.common.PortalManager;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.guing.common.exchange.AllocationHistory;
import org.opentcs.guing.common.exchange.ApplicationPortalProvider;
import org.opentcs.guing.common.exchange.adapter.VehicleAdapter;
import org.opentcs.operationsdesk.exchange.adapter.OpsDeskVehicleAdapter;
import org.opentcs.util.event.EventBus;
import org.opentcs.util.event.EventHandler;
import org.opentcs.util.event.EventSource;
import org.opentcs.util.event.SimpleEventBus;
/**
* A Guice configuration module for this package.
*/
public class ExchangeInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public ExchangeInjectionModule() {
}
@Override
protected void configure() {
bind(PortalManager.class)
.to(DefaultPortalManager.class)
.in(Singleton.class);
bind(KernelEventFetcher.class)
.in(Singleton.class);
EventBus eventBus = new SimpleEventBus();
bind(EventSource.class)
.annotatedWith(ApplicationEventBus.class)
.toInstance(eventBus);
bind(EventHandler.class)
.annotatedWith(ApplicationEventBus.class)
.toInstance(eventBus);
bind(EventBus.class)
.annotatedWith(ApplicationEventBus.class)
.toInstance(eventBus);
bind(SharedKernelServicePortalProvider.class)
.to(ApplicationPortalProvider.class)
.in(Singleton.class);
bind(AttributeAdapterRegistry.class)
.in(Singleton.class);
bind(OpenTCSEventDispatcher.class)
.in(Singleton.class);
bind(AllocationHistory.class)
.in(Singleton.class);
bind(VehicleAdapter.class)
.to(OpsDeskVehicleAdapter.class);
}
}

View File

@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.model;
import com.google.inject.AbstractModule;
import org.opentcs.guing.common.model.SystemModel;
/**
* A Guice module for the model package.
*/
public class ModelInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public ModelInjectionModule() {
}
@Override
protected void configure() {
bind(SystemModel.class).to(CachedSystemModel.class);
}
}

View File

@@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.notifications;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
/**
* A Guice module for this package.
*/
public class NotificationInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public NotificationInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(UserNotificationViewFactory.class));
bind(UserNotificationsContainer.class)
.in(Singleton.class);
}
}

View File

@@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.peripherals.jobs;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
/**
* A Guice module for this package.
*/
public class PeripheralJobInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public PeripheralJobInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(PeripheralJobViewFactory.class));
bind(PeripheralJobsContainer.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.persistence;
import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
import org.opentcs.guing.common.persistence.ModelFilePersistor;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.guing.common.persistence.OpenTCSModelManager;
import org.opentcs.guing.common.persistence.unified.UnifiedModelPersistor;
/**
* Default bindings for model readers and persistors.
*/
public class DefaultPersistenceInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public DefaultPersistenceInjectionModule() {
}
@Override
protected void configure() {
bind(ModelManager.class).to(OpenTCSModelManager.class).in(Singleton.class);
bind(ModelFilePersistor.class).to(UnifiedModelPersistor.class);
}
}

View File

@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.transport;
import java.util.HashSet;
import java.util.Set;
import org.opentcs.components.plantoverview.OrderTypeSuggestions;
import org.opentcs.data.order.OrderConstants;
/**
* The default suggestions for transport order types.
*/
public class DefaultOrderTypeSuggestions
implements
OrderTypeSuggestions {
/**
* The transport order type suggestions.
*/
private final Set<String> typeSuggestions = new HashSet<>();
/**
* Creates a new instance.
*/
public DefaultOrderTypeSuggestions() {
typeSuggestions.add(OrderConstants.TYPE_NONE);
typeSuggestions.add(OrderConstants.TYPE_CHARGE);
typeSuggestions.add(OrderConstants.TYPE_PARK);
typeSuggestions.add(OrderConstants.TYPE_TRANSPORT);
}
@Override
public Set<String> getTypeSuggestions() {
return typeSuggestions;
}
}

View File

@@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.transport;
import jakarta.inject.Singleton;
import org.opentcs.customizations.plantoverview.PlantOverviewInjectionModule;
import org.opentcs.guing.common.transport.OrderTypeSuggestionsPool;
/**
* A Guice module for the transport order type suggestions.
*/
public class OrderTypeSuggestionsModule
extends
PlantOverviewInjectionModule {
/**
* Creates a new instance.
*/
public OrderTypeSuggestionsModule() {
}
@Override
protected void configure() {
orderTypeSuggestionsBinder().addBinding()
.to(DefaultOrderTypeSuggestions.class)
.in(Singleton.class);
bind(OrderTypeSuggestionsPool.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.transport;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import jakarta.inject.Singleton;
import org.opentcs.operationsdesk.transport.orders.TransportOrdersContainer;
import org.opentcs.operationsdesk.transport.orders.TransportViewFactory;
import org.opentcs.operationsdesk.transport.sequences.OrderSequencesContainer;
/**
* A Guice module for this package.
*/
public class TransportInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public TransportInjectionModule() {
}
@Override
protected void configure() {
install(new FactoryModuleBuilder().build(TransportViewFactory.class));
bind(TransportOrdersContainer.class)
.in(Singleton.class);
bind(OrderSequencesContainer.class)
.in(Singleton.class);
}
}

View File

@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.util;
import com.google.inject.AbstractModule;
import jakarta.inject.Singleton;
import org.opentcs.guing.common.util.PanelRegistry;
/**
* A default Guice module for this package.
*/
public class UtilInjectionModule
extends
AbstractModule {
/**
* Creates a new instance.
*/
public UtilInjectionModule() {
}
@Override
protected void configure() {
bind(PanelRegistry.class).in(Singleton.class);
}
}

View File

@@ -0,0 +1,6 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: MIT
org.opentcs.operationsdesk.DefaultImportersExportersModule
org.opentcs.operationsdesk.PropertySuggestionsModule
org.opentcs.operationsdesk.transport.OrderTypeSuggestionsModule

View File

@@ -0,0 +1,176 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application;
import static java.util.Objects.requireNonNull;
import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import org.opentcs.common.ClientConnectionMode;
import org.opentcs.common.KernelClientApplication;
import org.opentcs.common.PortalManager;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.operationsdesk.util.OperationsDeskConfiguration;
import org.opentcs.util.event.EventBus;
import org.opentcs.util.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The application for kernel connections.
*/
public class OperationsDeskApplication
implements
KernelClientApplication,
EventHandler {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory
.getLogger(OperationsDeskApplication.class);
/**
* The portal manager.
*/
private final PortalManager portalManager;
/**
* The application's event bus.
*/
private final EventBus eventBus;
/**
* The application's configuration.
*/
private final OperationsDeskConfiguration configuration;
/**
* Whether this application is online or not.
*/
private ConnectionState connectionState = ConnectionState.OFFLINE;
/**
* Whether this application is initialized or not.
*/
private boolean initialized;
/**
* Creates a new instance.
*
* @param portalManager The service portal manager.
* @param eventBus The application's event bus.
* @param configuration The application's configuration.
*/
@Inject
@SuppressWarnings("this-escape")
public OperationsDeskApplication(
@Nonnull
PortalManager portalManager,
@ApplicationEventBus
EventBus eventBus,
OperationsDeskConfiguration configuration
) {
this.portalManager = requireNonNull(portalManager, "portalManager");
this.eventBus = requireNonNull(eventBus, "eventBus");
this.configuration = requireNonNull(configuration, "configuration");
}
@Override
public void initialize() {
if (isInitialized()) {
return;
}
eventBus.subscribe(this);
online(configuration.useBookmarksWhenConnecting());
initialized = true;
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void terminate() {
if (!isInitialized()) {
return;
}
eventBus.unsubscribe(this);
// If we want to terminate but are still online, go offline first
offline();
initialized = false;
}
@Override
public void onEvent(Object event) {
}
@Override
public void online(boolean autoConnect) {
if (isOnline() || isConnecting()) {
return;
}
connectionState = ConnectionState.CONNECTING;
if (portalManager.connect(toConnectionMode(autoConnect))) {
LOG.info("Switching application state to online...");
connectionState = ConnectionState.ONLINE;
eventBus.onEvent(ClientConnectionMode.ONLINE);
}
else {
connectionState = ConnectionState.OFFLINE;
}
}
@Override
public void offline() {
if (!isOnline() && !isConnecting()) {
return;
}
portalManager.disconnect();
LOG.info("Switching application state to offline...");
connectionState = ConnectionState.OFFLINE;
eventBus.onEvent(ClientConnectionMode.OFFLINE);
}
@Override
public boolean isOnline() {
return connectionState == ConnectionState.ONLINE;
}
/**
* Returns <code>true</code> if, and only if the operations desk is trying to establish a
* connection to the kernel.
*
* @return <code>true</code> if, and only if the operations desk is trying to establish a
* connection to the kernel
*/
public boolean isConnecting() {
return connectionState == ConnectionState.CONNECTING;
}
private PortalManager.ConnectionMode toConnectionMode(boolean autoConnect) {
return autoConnect ? PortalManager.ConnectionMode.AUTO : PortalManager.ConnectionMode.MANUAL;
}
/**
* An enum to display the different states of the operations desk application connection to the
* kernel.
*/
private enum ConnectionState {
/**
* The operations desk is not connected to the kernel and is not trying to.
*/
OFFLINE,
/**
* The operations desk is currently trying to connect to the kernel.
*/
CONNECTING,
/**
* The operations desk is connected to the kernel.
*/
ONLINE
}
}

View File

@@ -0,0 +1,162 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import org.jhotdraw.app.Application;
import org.opentcs.common.KernelClientApplication;
import org.opentcs.guing.common.application.ProgressIndicator;
import org.opentcs.guing.common.application.StartupProgressStatus;
import org.opentcs.guing.common.event.EventLogger;
import org.opentcs.operationsdesk.exchange.AttributeAdapterRegistry;
import org.opentcs.operationsdesk.exchange.KernelEventFetcher;
import org.opentcs.operationsdesk.exchange.OpenTCSEventDispatcher;
import org.opentcs.operationsdesk.notifications.UserNotificationsContainer;
import org.opentcs.operationsdesk.peripherals.jobs.PeripheralJobsContainer;
import org.opentcs.operationsdesk.transport.orders.TransportOrdersContainer;
import org.opentcs.operationsdesk.transport.sequences.OrderSequencesContainer;
/**
* The plant overview application's entry point.
*/
public class PlantOverviewStarter {
/**
* Our startup progress indicator.
*/
private final ProgressIndicator progressIndicator;
/**
* The enclosing application.
*/
private final Application application;
/**
* The actual document view.
*/
private final OpenTCSView opentcsView;
/**
*
*/
private final EventLogger eventLogger;
/**
* Fetches events from the kernel, if connected, and publishes them via the local event bus.
*/
private final KernelEventFetcher kernelEventFetcher;
/**
* Dispatches openTCS event from kernel objects to corresponding model components.
*/
private final OpenTCSEventDispatcher eventDispatcher;
/**
* Responsible for connections to a kernel.
*/
private final KernelClientApplication kernelClientApplication;
/**
* Handles registering of model attribute adapters.
*/
private final AttributeAdapterRegistry attributeAdapterRegistry;
/**
* Maintains a set of all transport orders existing on the kernel side.
*/
private final TransportOrdersContainer transportOrdersContainer;
/**
* Maintains a list of the most recent user notifications.
*/
private final UserNotificationsContainer userNotificationsContainer;
/**
* Maintains a set of all peripheral jobs existing on the kernel side.
*/
private final PeripheralJobsContainer peripheralJobsContainer;
/**
* Maintains a set of all order sequences existing on the kernel side.
*/
private final OrderSequencesContainer orderSequencesContainer;
/**
* Creates a new instance.
*
* @param progressIndicator The progress indicator to be used.
* @param application The application to be used.
* @param opentcsView The view to be used.
* @param eventLogger The event logger.
* @param kernelEventFetcher Fetches events from the kernel, if connected, and publishes them via
* the local event bus.
* @param eventDispatcher Dispatches openTCS event from kernel objects to corresponding model
* components.
* @param kernelClientApplication Responsible for connections to a kernel.
* @param attributeAdapterRegistry Handles registering of model attribute adapters.
* @param transportOrdersContainer Maintains a set of all transport orders existing on the kernel
* side.
* @param peripheralJobsContainer Maintains a set of all peripheral jobs existing on the kernel
* side.
* @param orderSequencesContainer Maintains a set of all peripheral jobs existing on the kernel
* side.
* @param userNotificationsContainer Maintains a list of the most recent user notifications.
*/
@Inject
public PlantOverviewStarter(
ProgressIndicator progressIndicator,
Application application,
OpenTCSView opentcsView,
EventLogger eventLogger,
KernelEventFetcher kernelEventFetcher,
OpenTCSEventDispatcher eventDispatcher,
KernelClientApplication kernelClientApplication,
AttributeAdapterRegistry attributeAdapterRegistry,
TransportOrdersContainer transportOrdersContainer,
PeripheralJobsContainer peripheralJobsContainer,
OrderSequencesContainer orderSequencesContainer,
UserNotificationsContainer userNotificationsContainer
) {
this.progressIndicator = requireNonNull(progressIndicator, "progressIndicator");
this.application = requireNonNull(application, "application");
this.opentcsView = requireNonNull(opentcsView, "opentcsView");
this.eventLogger = requireNonNull(eventLogger, "eventLogger");
this.kernelEventFetcher = requireNonNull(kernelEventFetcher, "kernelEventFetcher");
this.eventDispatcher = requireNonNull(eventDispatcher, "eventDispatcher");
this.kernelClientApplication = requireNonNull(
kernelClientApplication, "kernelClientApplication"
);
this.attributeAdapterRegistry = requireNonNull(
attributeAdapterRegistry,
"attributeAdapterRegistry"
);
this.transportOrdersContainer = requireNonNull(
transportOrdersContainer,
"transportOrdersContainer"
);
this.peripheralJobsContainer = requireNonNull(
peripheralJobsContainer,
"peripheralJobsContainer"
);
this.orderSequencesContainer = requireNonNull(
orderSequencesContainer,
"orderSequencesContainer"
);
this.userNotificationsContainer = requireNonNull(
userNotificationsContainer,
"userNotificationsContainer"
);
}
public void startPlantOverview() {
eventLogger.initialize();
kernelEventFetcher.initialize();
eventDispatcher.initialize();
attributeAdapterRegistry.initialize();
transportOrdersContainer.initialize();
peripheralJobsContainer.initialize();
orderSequencesContainer.initialize();
userNotificationsContainer.initialize();
opentcsView.init();
progressIndicator.initialize();
progressIndicator.setProgress(StartupProgressStatus.START_PLANT_OVERVIEW);
progressIndicator.setProgress(StartupProgressStatus.SHOW_PLANT_OVERVIEW);
opentcsView.setApplication(application);
// Start the view.
application.show(opentcsView);
kernelClientApplication.initialize();
progressIndicator.terminate();
}
}

View File

@@ -0,0 +1,353 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application;
import static java.util.Objects.requireNonNull;
import bibliothek.gui.Dockable;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.intern.DefaultCommonDockable;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.guing.common.application.AbstractViewManager;
import org.opentcs.guing.common.components.dockable.CStackDockStation;
import org.opentcs.guing.common.components.dockable.DockableTitleComparator;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.operationsdesk.components.dockable.DockingManagerOperating;
import org.opentcs.operationsdesk.notifications.UserNotificationsContainerPanel;
import org.opentcs.operationsdesk.peripherals.jobs.PeripheralJobsContainerPanel;
import org.opentcs.operationsdesk.transport.orders.TransportOrdersContainerPanel;
import org.opentcs.operationsdesk.transport.sequences.OrderSequencesContainerPanel;
import org.opentcs.util.event.EventSource;
/**
* Manages the mapping of dockables to drawing views, transport order views and
* order sequence views.
*/
public class ViewManagerOperating
extends
AbstractViewManager {
/**
* Manages the application's docking frames.
*/
private final DockingManagerOperating dockingManager;
/**
* Where we register event listeners.
*/
private final EventSource eventSource;
/**
* Map for user notification dockable -> user notification container panel.
*/
private final Map<DefaultSingleCDockable, UserNotificationsContainerPanel> userNotificationViews;
/**
* Map for transport order dockable -> transport order container panel.
*/
private final Map<DefaultSingleCDockable, TransportOrdersContainerPanel> transportOrderViews;
/**
* Map for order sequences dockable -> order sequences container panel.
*/
private final Map<DefaultSingleCDockable, OrderSequencesContainerPanel> orderSequenceViews;
/**
* Map for peripheral job dockable -> peripheral job container panel.
*/
private final Map<DefaultSingleCDockable, PeripheralJobsContainerPanel> peripheralJobViews;
/**
* Creates a new instance.
*
* @param dockingManager Manages the application's docking frames.
* @param eventSource Where this instance registers event listeners.
*/
@Inject
public ViewManagerOperating(
DockingManagerOperating dockingManager,
@ApplicationEventBus
EventSource eventSource
) {
super(eventSource);
this.dockingManager = requireNonNull(dockingManager, "dockingManager");
this.eventSource = requireNonNull(eventSource, "eventSource");
userNotificationViews = new TreeMap<>(new DockableTitleComparator());
transportOrderViews = new TreeMap<>(new DockableTitleComparator());
orderSequenceViews = new TreeMap<>(new DockableTitleComparator());
peripheralJobViews = new TreeMap<>(new DockableTitleComparator());
}
public void init() {
setPlantOverviewStateOperating();
}
/**
* Resets all components.
*/
public void reset() {
super.reset();
userNotificationViews.clear();
transportOrderViews.clear();
orderSequenceViews.clear();
peripheralJobViews.clear();
}
public Map<DefaultSingleCDockable, UserNotificationsContainerPanel> getUserNotificationMap() {
return userNotificationViews;
}
public Map<DefaultSingleCDockable, TransportOrdersContainerPanel> getTransportOrderMap() {
return transportOrderViews;
}
public Map<DefaultSingleCDockable, OrderSequencesContainerPanel> getOrderSequenceMap() {
return orderSequenceViews;
}
public Map<DefaultSingleCDockable, PeripheralJobsContainerPanel> getPeripheralJobMap() {
return peripheralJobViews;
}
/**
* Returns all drawing views (excluding the modelling view)
*
* @return List with all known <code>OpenTCSDrawingViews</code>, but not
* the modelling view.
*/
public List<OpenTCSDrawingView> getOperatingDrawingViews() {
return getDrawingViewMap().entrySet().stream()
.map(entry -> entry.getValue().getDrawingView())
.collect(Collectors.toList());
}
public int getNextUserNotificationViewIndex() {
return nextAvailableIndex(userNotificationViews.keySet());
}
public int getNextTransportOrderViewIndex() {
return nextAvailableIndex(transportOrderViews.keySet());
}
public int getNextOrderSequenceViewIndex() {
return nextAvailableIndex(orderSequenceViews.keySet());
}
public int getNextPeripheralJobViewIndex() {
return nextAvailableIndex(peripheralJobViews.keySet());
}
public DefaultSingleCDockable getLastUserNotificationView() {
int biggestIndex = getNextUserNotificationViewIndex();
DefaultSingleCDockable lastUNView = null;
Iterator<DefaultSingleCDockable> userNotificationViewIterator
= userNotificationViews.keySet().iterator();
for (int i = 0; i < biggestIndex; i++) {
if (userNotificationViewIterator.hasNext()) {
lastUNView = userNotificationViewIterator.next();
}
}
return lastUNView;
}
public DefaultSingleCDockable getLastTransportOrderView() {
int biggestIndex = getNextTransportOrderViewIndex();
DefaultSingleCDockable lastTOView = null;
Iterator<DefaultSingleCDockable> tranportOrderViewIterator
= transportOrderViews.keySet().iterator();
for (int i = 0; i < biggestIndex; i++) {
if (tranportOrderViewIterator.hasNext()) {
lastTOView = tranportOrderViewIterator.next();
}
}
return lastTOView;
}
public DefaultSingleCDockable getLastOrderSequenceView() {
int biggestIndex = getNextOrderSequenceViewIndex();
DefaultSingleCDockable lastOSView = null;
Iterator<DefaultSingleCDockable> orderSequencesViewIterator
= orderSequenceViews.keySet().iterator();
for (int i = 0; i < biggestIndex; i++) {
if (orderSequencesViewIterator.hasNext()) {
lastOSView = orderSequencesViewIterator.next();
}
}
return lastOSView;
}
public DefaultSingleCDockable getLastPeripheralJobView() {
int biggestIndex = getNextPeripheralJobViewIndex();
DefaultSingleCDockable lastView = null;
Iterator<DefaultSingleCDockable> peripheralJobViewIterator
= peripheralJobViews.keySet().iterator();
for (int i = 0; i < biggestIndex; i++) {
if (peripheralJobViewIterator.hasNext()) {
lastView = peripheralJobViewIterator.next();
}
}
return lastView;
}
/**
* Puts a <code>UserNotificationsContainerPanel</code> with a key dockable
* into the user notification view map.
*
* @param dockable The dockable the panel is wrapped into. Used as the key.
* @param panel The panel.
*/
public void addUserNotificationView(
DefaultSingleCDockable dockable,
UserNotificationsContainerPanel panel
) {
requireNonNull(dockable, "dockable");
requireNonNull(panel, "panel");
userNotificationViews.put(dockable, panel);
}
/**
* Puts a <code>TransportOrdersContainerPanel</code> with a key dockable
* into the transport order view map.
*
* @param dockable The dockable the panel is wrapped into. Used as the key.
* @param panel The panel.
*/
public void addTransportOrderView(
DefaultSingleCDockable dockable,
TransportOrdersContainerPanel panel
) {
requireNonNull(dockable, "dockable");
requireNonNull(panel, "panel");
transportOrderViews.put(dockable, panel);
}
/**
* Puts a <code>OrderSequencesContainerPanel</code> with a key dockable
* into the order sequence view map.
*
* @param dockable The dockable the panel is wrapped into. Used as the key.
* @param panel The panel.
*/
public void addOrderSequenceView(
DefaultSingleCDockable dockable,
OrderSequencesContainerPanel panel
) {
requireNonNull(dockable, "dockable");
requireNonNull(panel, "panel");
orderSequenceViews.put(dockable, panel);
}
/**
* Puts a <code>OrderSequencesContainerPanel</code> with a key dockable
* into the order sequence view map.
*
* @param dockable The dockable the panel is wrapped into. Used as the key.
* @param panel The panel.
*/
public void addPeripheralJobView(
DefaultSingleCDockable dockable,
PeripheralJobsContainerPanel panel
) {
requireNonNull(dockable, "dockable");
requireNonNull(panel, "panel");
peripheralJobViews.put(dockable, panel);
}
/**
* Forgets the given dockable.
*
* @param dockable The dockable.
*/
@Override
public void removeDockable(DefaultSingleCDockable dockable) {
super.removeDockable(dockable);
transportOrderViews.remove(dockable);
orderSequenceViews.remove(dockable);
peripheralJobViews.remove(dockable);
}
/**
* Evaluates which dockable should be the front dockable.
*
* @return The dockable that should be the front dockable. <code>null</code>
* if no dockables exist.
*/
@Override
public DefaultCommonDockable evaluateFrontDockable() {
if (!getDrawingViewMap().isEmpty()) {
return getDrawingViewMap().keySet().iterator().next().intern();
}
if (!transportOrderViews.isEmpty()) {
return transportOrderViews.keySet().iterator().next().intern();
}
if (!orderSequenceViews.isEmpty()) {
return orderSequenceViews.keySet().iterator().next().intern();
}
if (!peripheralJobViews.isEmpty()) {
return peripheralJobViews.keySet().iterator().next().intern();
}
return null;
}
/**
* Sets visibility states of all dockables to operating.
*/
private void setPlantOverviewStateOperating() {
CStackDockStation station
= dockingManager.getTabPane(DockingManagerOperating.COURSE_TAB_PANE_ID).getStation();
Dockable frontDock = station.getFrontDockable();
int i = 0;
for (DefaultSingleCDockable dock : new ArrayList<>(getDrawingViewMap().keySet())) {
// Restore to default
dock.setCloseable(true);
dockingManager.showDockable(station, dock, i);
i++;
}
i = getDrawingViewMap().size();
for (DefaultSingleCDockable dock : new ArrayList<>(getDrawingViewMap().keySet())) {
// OpenTCSDrawingViews can be undocked when switching states, so
// we make sure they aren't counted as docked
if (dockingManager.isDockableDocked(station, dock)) {
i--;
}
}
int dockedDrawingViews = i;
for (DefaultSingleCDockable dock : new ArrayList<>(transportOrderViews.keySet())) {
dockingManager.showDockable(station, dock, i);
i++;
}
i = dockedDrawingViews + transportOrderViews.size();
for (DefaultSingleCDockable dock : new ArrayList<>(orderSequenceViews.keySet())) {
dockingManager.showDockable(station, dock, i);
i++;
}
for (DefaultSingleCDockable dock : new ArrayList<>(peripheralJobViews.keySet())) {
dockingManager.showDockable(station, dock, i);
i++;
}
if (frontDock != null && frontDock.isDockableShowing()) {
station.setFrontDockable(frontDock);
}
else {
station.setFrontDockable(station.getDockable(0));
}
dockingManager.setDockableVisibility(DockingManagerOperating.VEHICLES_DOCKABLE_ID, true);
}
}

View File

@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action;
import java.util.Collection;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.order.ReroutingType;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.operationsdesk.application.action.course.FollowVehicleAction;
import org.opentcs.operationsdesk.application.action.course.IntegrationLevelChangeAction;
import org.opentcs.operationsdesk.application.action.course.PauseAction;
import org.opentcs.operationsdesk.application.action.course.RerouteAction;
import org.opentcs.operationsdesk.application.action.course.ScrollToVehicleAction;
import org.opentcs.operationsdesk.application.action.course.SendVehicleToLocationAction;
import org.opentcs.operationsdesk.application.action.course.SendVehicleToPointAction;
import org.opentcs.operationsdesk.application.action.course.WithdrawAction;
/**
* A factory for various actions.
*/
public interface ActionFactory {
ScrollToVehicleAction createScrollToVehicleAction(VehicleModel vehicleModel);
FollowVehicleAction createFollowVehicleAction(VehicleModel vehicleModel);
SendVehicleToPointAction createSendVehicleToPointAction(VehicleModel vehicleModel);
SendVehicleToLocationAction createSendVehicleToLocationAction(VehicleModel vehicleModel);
WithdrawAction createWithdrawAction(Collection<VehicleModel> vehicles, boolean immediateAbort);
IntegrationLevelChangeAction createIntegrationLevelChangeAction(
Collection<VehicleModel> vehicles,
Vehicle.IntegrationLevel level
);
PauseAction createPauseAction(Collection<VehicleModel> vehicles, boolean pause);
RerouteAction createRerouteAction(
Collection<VehicleModel> vehicles,
ReroutingType reroutingType
);
}

View File

@@ -0,0 +1,305 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.event.KernelStateChangeEvent.State.LOGGED_IN;
import jakarta.inject.Inject;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.Action;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import org.jhotdraw.draw.DrawingEditor;
import org.jhotdraw.draw.event.ToolAdapter;
import org.jhotdraw.draw.event.ToolEvent;
import org.jhotdraw.draw.event.ToolListener;
import org.opentcs.guing.common.application.action.ToolButtonListener;
import org.opentcs.guing.common.application.toolbar.DragTool;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.event.ResetInteractionToolCommand;
import org.opentcs.guing.common.util.CourseObjectFactory;
import org.opentcs.guing.common.util.ImageDirectory;
import org.opentcs.operationsdesk.application.action.actions.CreateTransportOrderAction;
import org.opentcs.operationsdesk.application.action.actions.FindVehicleAction;
import org.opentcs.operationsdesk.application.action.actions.PauseAllVehiclesAction;
import org.opentcs.operationsdesk.application.action.actions.ResumeAllVehiclesAction;
import org.opentcs.operationsdesk.application.toolbar.MultipleSelectionTool;
import org.opentcs.operationsdesk.application.toolbar.SelectionToolFactory;
import org.opentcs.operationsdesk.event.KernelStateChangeEvent;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.action.draw.SelectSameAction;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.opentcs.util.event.EventHandler;
/**
* Sets up and manages a list of tool bars in the graphical user interface.
*/
public class ToolBarManager
implements
EventHandler {
/**
* A factory for selectiont tools.
*/
private final SelectionToolFactory selectionToolFactory;
/**
* A list of all toolbars.
*/
private final List<JToolBar> toolBarList = Collections.synchronizedList(new ArrayList<>());
/**
* A tool bar for actions creating new items.
*/
private final JToolBar toolBarCreation = new JToolBar();
/**
* A toggle button for the selection tool.
*/
private final JToggleButton selectionToolButton;
/**
* A toggle button for the drag tool.
*/
private final JToggleButton dragToolButton;
/**
* The actual drag tool.
*/
private DragTool dragTool;
/**
* A button for creating transport orders.
* Available in operating mode.
*/
private final JButton buttonCreateOrder;
/**
* A button for finding vehicles.
* Available in operating mode.
*/
private final JButton buttonFindVehicle;
/**
* A button for pausing all vehicles.
* Available in operating mode.
*/
private final JButton buttonPauseAllVehicles;
/**
* A button for resuming all vehicles.
* Available in operating mode.
*/
private final JButton buttonResumeAllVehicles;
/**
* Creates a new instance.
*
* @param actionMap The action map to be used
* @param crsObjFactory A factory for course objects
* @param editor The drawing editor
* @param selectionToolFactory The selection tool factory
*/
@Inject
public ToolBarManager(
ViewActionMap actionMap,
CourseObjectFactory crsObjFactory,
OpenTCSDrawingEditor editor,
SelectionToolFactory selectionToolFactory
) {
requireNonNull(actionMap, "actionMap");
requireNonNull(crsObjFactory, "crsObjFactory");
requireNonNull(editor, "editor");
this.selectionToolFactory = requireNonNull(
selectionToolFactory,
"selectionToolFactory"
);
ResourceBundleUtil labels
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.TOOLBAR_PATH);
// --- 1. ToolBar: Creation ---
// Selection, Drag | Create Point, Location, Path, Link |
// Create Location Type, Vehicle, Block, Static Route |
// Create Transport Order | Find, Show Vehicles
toolBarCreation.setActionMap(actionMap);
// --- Selection Tool ---
selectionToolButton = addSelectionToolButton(toolBarCreation, editor);
// --- Drag Tool ---
dragToolButton = addDragToolButton(toolBarCreation, editor);
toolBarCreation.addSeparator();
// --- Create Transport Order (only in Operating mode) ---
buttonCreateOrder = new JButton(actionMap.get(CreateTransportOrderAction.ID));
buttonCreateOrder.setText(null);
buttonCreateOrder.setEnabled(false);
toolBarCreation.add(buttonCreateOrder);
toolBarCreation.addSeparator();
// --- Find Vehicle (only in Operating mode) ---
buttonFindVehicle = new JButton(actionMap.get(FindVehicleAction.ID));
buttonFindVehicle.setText(null);
buttonFindVehicle.setEnabled(false);
toolBarCreation.add(buttonFindVehicle);
toolBarCreation.addSeparator();
// --- Pause All Vehicles (only in Operating mode) ---
buttonPauseAllVehicles = new JButton(actionMap.get(PauseAllVehiclesAction.ID));
buttonPauseAllVehicles.setText(null);
buttonPauseAllVehicles.setEnabled(false);
toolBarCreation.add(buttonPauseAllVehicles);
// --- Resume All Vehicles (only in Operating mode) ---
buttonResumeAllVehicles = new JButton(actionMap.get(ResumeAllVehiclesAction.ID));
buttonResumeAllVehicles.setText(null);
buttonResumeAllVehicles.setEnabled(false);
toolBarCreation.add(buttonResumeAllVehicles);
toolBarCreation.setName(labels.getString("toolBarManager.toolbar_drawing.title"));
toolBarList.add(toolBarCreation);
}
public List<JToolBar> getToolBars() {
return toolBarList;
}
public JToolBar getToolBarCreation() {
return toolBarCreation;
}
public JToggleButton getSelectionToolButton() {
return selectionToolButton;
}
public JToggleButton getDragToolButton() {
return dragToolButton;
}
@Override
public void onEvent(Object event) {
if (event instanceof ResetInteractionToolCommand resetInteractionToolCommand) {
handleToolReset(resetInteractionToolCommand);
}
else if (event instanceof KernelStateChangeEvent kernelStateChangeEvent) {
handleKernelStateChangeEvent(kernelStateChangeEvent);
}
}
private void handleToolReset(ResetInteractionToolCommand evt) {
selectionToolButton.setSelected(true);
}
private void handleKernelStateChangeEvent(KernelStateChangeEvent event) {
switch (event.getNewState()) {
case LOGGED_IN:
buttonCreateOrder.setEnabled(true);
buttonFindVehicle.setEnabled(true);
buttonPauseAllVehicles.setEnabled(true);
buttonResumeAllVehicles.setEnabled(true);
break;
case DISCONNECTED:
buttonCreateOrder.setEnabled(false);
buttonFindVehicle.setEnabled(false);
buttonPauseAllVehicles.setEnabled(false);
buttonResumeAllVehicles.setEnabled(false);
break;
default:
// Do nothing.
}
}
/**
* Adds the selection tool to the given toolbar.
*
* @param toolBar The toolbar to add to.
* @param editor The DrawingEditor.
*/
private JToggleButton addSelectionToolButton(
JToolBar toolBar,
DrawingEditor editor
) {
List<Action> drawingActions = new ArrayList<>();
// Drawing Actions
drawingActions.add(new SelectSameAction(editor));
MultipleSelectionTool selectionTool
= selectionToolFactory.createMultipleSelectionTool(drawingActions, new ArrayList<>());
ButtonGroup buttonGroup;
if (toolBar.getClientProperty("toolButtonGroup") instanceof ButtonGroup) {
buttonGroup = (ButtonGroup) toolBar.getClientProperty("toolButtonGroup");
}
else {
buttonGroup = new ButtonGroup();
toolBar.putClientProperty("toolButtonGroup", buttonGroup);
}
// Selection tool
editor.setTool(selectionTool);
final JToggleButton toggleButton = new JToggleButton();
if (!(toolBar.getClientProperty("toolHandler") instanceof ToolListener)) {
ToolListener toolHandler = new ToolAdapter() {
@Override
public void toolDone(ToolEvent event) {
toggleButton.setSelected(true);
}
};
toolBar.putClientProperty("toolHandler", toolHandler);
}
toggleButton.setIcon(ImageDirectory.getImageIcon("/toolbar/select-2.png"));
toggleButton.setText(null);
toggleButton.setToolTipText(
ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.TOOLBAR_PATH)
.getString("toolBarManager.button_selectionTool.tooltipText")
);
toggleButton.setSelected(true);
toggleButton.addItemListener(new ToolButtonListener(selectionTool, editor));
buttonGroup.add(toggleButton);
toolBar.add(toggleButton);
return toggleButton;
}
/**
*
* @param toolBar
* @param editor
*/
private JToggleButton addDragToolButton(JToolBar toolBar, DrawingEditor editor) {
final JToggleButton button = new JToggleButton();
dragTool = new DragTool();
editor.setTool(dragTool);
if (!(toolBar.getClientProperty("toolHandler") instanceof ToolListener)) {
ToolListener toolHandler = new ToolAdapter() {
@Override
public void toolDone(ToolEvent event) {
button.setSelected(true);
}
};
toolBar.putClientProperty("toolHandler", toolHandler);
}
URL url = getClass().getResource(ImageDirectory.DIR + "/toolbar/cursor-opened-hand.png");
button.setIcon(new ImageIcon(url));
button.setText(null);
button.setToolTipText(
ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.TOOLBAR_PATH)
.getString("toolBarManager.button_dragTool.tooltipText")
);
button.setSelected(false);
button.addItemListener(new ToolButtonListener(dragTool, editor));
ButtonGroup group = (ButtonGroup) toolBar.getClientProperty("toolButtonGroup");
group.add(button);
toolBar.add(button);
return button;
}
}

View File

@@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import javax.swing.ActionMap;
import org.opentcs.common.KernelClientApplication;
import org.opentcs.guing.common.application.action.file.ModelPropertiesAction;
import org.opentcs.guing.common.application.action.file.SaveModelAction;
import org.opentcs.guing.common.application.action.file.SaveModelAsAction;
import org.opentcs.operationsdesk.application.OpenTCSView;
import org.opentcs.operationsdesk.application.action.actions.ConnectToKernelAction;
import org.opentcs.operationsdesk.application.action.actions.CreatePeripheralJobAction;
import org.opentcs.operationsdesk.application.action.actions.CreateTransportOrderAction;
import org.opentcs.operationsdesk.application.action.actions.DisconnectFromKernelAction;
import org.opentcs.operationsdesk.application.action.actions.FindVehicleAction;
import org.opentcs.operationsdesk.application.action.actions.PauseAllVehiclesAction;
import org.opentcs.operationsdesk.application.action.actions.ResumeAllVehiclesAction;
import org.opentcs.operationsdesk.application.action.app.AboutAction;
import org.opentcs.operationsdesk.application.action.view.AddDrawingViewAction;
import org.opentcs.operationsdesk.application.action.view.AddPeripheralJobViewAction;
import org.opentcs.operationsdesk.application.action.view.AddTransportOrderSequenceViewAction;
import org.opentcs.operationsdesk.application.action.view.AddTransportOrderViewAction;
import org.opentcs.operationsdesk.application.action.view.RestoreDockingLayoutAction;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.action.edit.DeleteAction;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.action.edit.SelectAllAction;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.action.edit.UndoRedoManager;
import org.opentcs.thirdparty.operationsdesk.jhotdraw.application.action.file.CloseFileAction;
/**
* A custom ActionMap for the plant overview application.
*/
public class ViewActionMap
extends
ActionMap {
/**
* Creates a new instance.
*
* @param view The openTCS view
* @param undoRedoManager The undo redo manager
* @param kernelClientApplication The kernel-client application
* @param actionFactory The action factory
* @param createTransportOrderAction The action to create transport orders
* @param findVehicleAction The action to find vehicles
* @param pauseAllVehiclesAction The action to pause all vehicles
* @param resumeAllVehiclesAction The action to resume all vehicles
* @param aboutAction The action to show the about window
* @param modelPropertiesAction The action to show some model properties.
* @param createPeripheralJobAction The action to create peripheral jobs.
*/
@Inject
@SuppressWarnings("this-escape")
public ViewActionMap(
OpenTCSView view,
UndoRedoManager undoRedoManager,
KernelClientApplication kernelClientApplication,
ActionFactory actionFactory,
CreateTransportOrderAction createTransportOrderAction,
FindVehicleAction findVehicleAction,
PauseAllVehiclesAction pauseAllVehiclesAction,
ResumeAllVehiclesAction resumeAllVehiclesAction,
AboutAction aboutAction,
ModelPropertiesAction modelPropertiesAction,
CreatePeripheralJobAction createPeripheralJobAction
) {
requireNonNull(view, "view");
requireNonNull(undoRedoManager, "undoRedoManager");
requireNonNull(kernelClientApplication, "kernelClientApplication");
requireNonNull(actionFactory, "actionFactory");
requireNonNull(createTransportOrderAction, "createTransportOrderAction");
requireNonNull(findVehicleAction, "findVehicleAction");
requireNonNull(pauseAllVehiclesAction, "pauseAllVehiclesAction");
requireNonNull(resumeAllVehiclesAction, "resumeAllVehiclesAction");
requireNonNull(aboutAction, "aboutAction");
requireNonNull(createPeripheralJobAction, "createPeripheralJobAction");
// --- Menu File ---
put(SaveModelAction.ID, new SaveModelAction(view));
put(SaveModelAsAction.ID, new SaveModelAsAction(view));
put(ModelPropertiesAction.ID, modelPropertiesAction);
put(CloseFileAction.ID, new CloseFileAction(view));
put(ConnectToKernelAction.ID, new ConnectToKernelAction(kernelClientApplication));
put(DisconnectFromKernelAction.ID, new DisconnectFromKernelAction(kernelClientApplication));
// --- Menu Edit ---
// Undo, Redo
put(UndoRedoManager.UNDO_ACTION_ID, undoRedoManager.getUndoAction());
put(UndoRedoManager.REDO_ACTION_ID, undoRedoManager.getRedoAction());
// Cut, Copy, Paste, Duplicate, Delete
put(DeleteAction.ID, new DeleteAction());
// Select all
put(SelectAllAction.ID, new SelectAllAction());
// --- Menu Actions ---
// Menu item Actions -> Create ...
put(CreateTransportOrderAction.ID, createTransportOrderAction);
put(CreatePeripheralJobAction.ID, createPeripheralJobAction);
// --- Menu View ---
// Menu View -> Add drawing view
put(AddDrawingViewAction.ID, new AddDrawingViewAction(view));
// Menu View -> Add transport order view
put(AddTransportOrderViewAction.ID, new AddTransportOrderViewAction(view));
// Menu View -> Add transport order sequence view
put(AddTransportOrderSequenceViewAction.ID, new AddTransportOrderSequenceViewAction(view));
put(AddPeripheralJobViewAction.ID, new AddPeripheralJobViewAction(view));
put(RestoreDockingLayoutAction.ID, new RestoreDockingLayoutAction(view));
put(FindVehicleAction.ID, findVehicleAction);
put(PauseAllVehiclesAction.ID, pauseAllVehiclesAction);
put(ResumeAllVehiclesAction.ID, resumeAllVehiclesAction);
// --- Menu Help ---
put(AboutAction.ID, aboutAction);
}
}

View File

@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.common.KernelClientApplication;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action to connect to a kernel.
*/
public class ConnectToKernelAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "file.connectToKernel";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
private final KernelClientApplication application;
/**
* Creates a new instance.
*
* @param application The kernel client application.
*/
@SuppressWarnings("this-escape")
public ConnectToKernelAction(KernelClientApplication application) {
this.application = requireNonNull(application, "application");
putValue(NAME, BUNDLE.getString("connectToKernelAction.name"));
}
@Override
public void actionPerformed(ActionEvent evt) {
application.online(false);
}
}

View File

@@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static javax.swing.Action.MNEMONIC_KEY;
import static javax.swing.Action.NAME;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.access.KernelRuntimeException;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.access.to.peripherals.PeripheralJobCreationTO;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.common.components.dialogs.StandardContentDialog;
import org.opentcs.operationsdesk.transport.CreatePeripheralJobPanel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An action to trigger the creation of a peripheral job.
*/
public class CreatePeripheralJobAction
extends
AbstractAction {
/**
* This action class's ID.
*/
public static final String ID = "actions.createPeripheralJob";
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(CreatePeripheralJobAction.class);
/**
* Access to the resource bundle.
*/
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
/**
* The parent component for dialogs show by this action.
*/
private final Component dialogParent;
/**
* Provides panels for entering a new peripheral job.
*/
private final Provider<CreatePeripheralJobPanel> jobPanelProvider;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* Creates a new instance.
*
* @param dialogParent The parent for dialogs shown by this action.
* @param peripheralJobPanel Provides panels for entering new peripheral jobs.
* @param portalProvider Provides access to the kernel service portal.
*/
@Inject
@SuppressWarnings("this-escape")
public CreatePeripheralJobAction(
@ApplicationFrame
Component dialogParent,
Provider<CreatePeripheralJobPanel> peripheralJobPanel,
SharedKernelServicePortalProvider portalProvider
) {
this.dialogParent = requireNonNull(dialogParent, "dialogParent");
this.jobPanelProvider = requireNonNull(peripheralJobPanel, "peripheralJobPanel");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
putValue(NAME, BUNDLE.getString("createPeripheralJobAction.name"));
putValue(MNEMONIC_KEY, Integer.valueOf('P'));
}
@Override
public void actionPerformed(ActionEvent e) {
CreatePeripheralJobPanel contentPanel = jobPanelProvider.get();
StandardContentDialog dialog = new StandardContentDialog(dialogParent, contentPanel);
dialog.setVisible(true);
if (dialog.getReturnStatus() != StandardContentDialog.RET_OK) {
return;
}
PeripheralJobCreationTO job
= new PeripheralJobCreationTO(
"Job-",
contentPanel.getReservationToken(),
contentPanel.getPeripheralOperation()
)
.withIncompleteName(true);
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
sharedPortal.getPortal().getPeripheralJobService().createPeripheralJob(job);
sharedPortal.getPortal().getPeripheralDispatcherService().dispatch();
}
catch (KernelRuntimeException exception) {
LOG.warn("Unexpected exception", exception);
}
}
}

View File

@@ -0,0 +1,108 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static javax.swing.Action.LARGE_ICON_KEY;
import static javax.swing.Action.MNEMONIC_KEY;
import static javax.swing.Action.SMALL_ICON;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.common.components.dialogs.StandardContentDialog;
import org.opentcs.guing.common.transport.OrderTypeSuggestionsPool;
import org.opentcs.guing.common.util.ImageDirectory;
import org.opentcs.operationsdesk.exchange.TransportOrderUtil;
import org.opentcs.operationsdesk.transport.CreateTransportOrderPanel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action to trigger the creation of a transport order.
*/
public class CreateTransportOrderAction
extends
AbstractAction {
/**
* This action class's ID.
*/
public static final String ID = "actions.createTransportOrder";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
/**
* A helper for creating transport orders with the kernel.
*/
private final TransportOrderUtil orderUtil;
/**
* The parent component for dialogs shown by this action.
*/
private final Component dialogParent;
/**
* Provides panels for entering new transport orders.
*/
private final Provider<CreateTransportOrderPanel> orderPanelProvider;
/**
* The pool of suggested transport order types.
*/
private final OrderTypeSuggestionsPool typeSuggestionsPool;
/**
* Creates a new instance.
*
* @param orderUtil A helper for creating transport orders with the kernel.
* @param dialogParent The parent component for dialogs shown by this action.
* @param orderPanelProvider Provides panels for entering new transport orders.
* @param typeSuggestionsPool The pool of suggested transport order types.
*/
@Inject
@SuppressWarnings("this-escape")
public CreateTransportOrderAction(
TransportOrderUtil orderUtil,
@ApplicationFrame
Component dialogParent,
Provider<CreateTransportOrderPanel> orderPanelProvider,
OrderTypeSuggestionsPool typeSuggestionsPool
) {
this.orderUtil = requireNonNull(orderUtil, "orderUtil");
this.dialogParent = requireNonNull(dialogParent, "dialogParent");
this.orderPanelProvider = requireNonNull(orderPanelProvider, "orderPanelProvider");
this.typeSuggestionsPool = requireNonNull(typeSuggestionsPool, "typeSuggestionsPool");
putValue(NAME, BUNDLE.getString("createTransportOrderAction.name"));
putValue(MNEMONIC_KEY, Integer.valueOf('T'));
ImageIcon icon = ImageDirectory.getImageIcon("/toolbar/create-order.22.png");
putValue(SMALL_ICON, icon);
putValue(LARGE_ICON_KEY, icon);
}
@Override
public void actionPerformed(ActionEvent evt) {
createTransportOrder();
}
public void createTransportOrder() {
CreateTransportOrderPanel contentPanel = orderPanelProvider.get();
StandardContentDialog dialog = new StandardContentDialog(dialogParent, contentPanel);
dialog.setVisible(true);
if (dialog.getReturnStatus() != StandardContentDialog.RET_OK) {
return;
}
orderUtil.createTransportOrder(
contentPanel.getDestinationModels(),
contentPanel.getActions(),
contentPanel.getSelectedDeadline(),
contentPanel.getSelectedVehicle(),
contentPanel.getSelectedType()
);
typeSuggestionsPool.addTypeSuggestion(contentPanel.getSelectedType());
}
}

View File

@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.common.KernelClientApplication;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action to disconnect from a kernel.
*/
public class DisconnectFromKernelAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "file.disconnectFromKernel";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
private final KernelClientApplication application;
/**
* Creates a new instance.
*
* @param application The kernel client application.
*/
@SuppressWarnings("this-escape")
public DisconnectFromKernelAction(KernelClientApplication application) {
this.application = requireNonNull(application, "application");
putValue(NAME, BUNDLE.getString("disconnectFromKernelAction.name"));
}
@Override
public void actionPerformed(ActionEvent evt) {
application.offline();
}
}

View File

@@ -0,0 +1,114 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static javax.swing.Action.LARGE_ICON_KEY;
import static javax.swing.Action.MNEMONIC_KEY;
import static javax.swing.Action.SMALL_ICON;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import jakarta.inject.Inject;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.dialogs.ClosableDialog;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.guing.common.util.ImageDirectory;
import org.opentcs.operationsdesk.components.dialogs.FindVehiclePanel;
import org.opentcs.operationsdesk.components.dialogs.FindVehiclePanelFactory;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action to find a vehicle on the drawing.
*/
public class FindVehicleAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "actions.findVehicle";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* The drawing editor.
*/
private final OpenTCSDrawingEditor drawingEditor;
/**
* The parent component for dialogs shown by this action.
*/
private final Component dialogParent;
/**
* The panel factory.
*/
private final FindVehiclePanelFactory panelFactory;
/**
* Creates a new instance.
*
* @param modelManager Provides the current system model.
* @param drawingEditor The drawing editor.
* @param dialogParent The parent component for dialogs shown by this action.
* @param panelFactory The panel factory.
*/
@Inject
@SuppressWarnings("this-escape")
public FindVehicleAction(
ModelManager modelManager,
OpenTCSDrawingEditor drawingEditor,
@ApplicationFrame
Component dialogParent,
FindVehiclePanelFactory panelFactory
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.drawingEditor = requireNonNull(drawingEditor, "drawingEditor");
this.dialogParent = requireNonNull(dialogParent, "dialogParent");
this.panelFactory = requireNonNull(panelFactory, "panelFactory");
putValue(NAME, BUNDLE.getString("findVehicleAction.name"));
putValue(MNEMONIC_KEY, Integer.valueOf('F'));
ImageIcon icon = ImageDirectory.getImageIcon("/toolbar/find-vehicle.22.png");
putValue(SMALL_ICON, icon);
putValue(LARGE_ICON_KEY, icon);
}
@Override
public void actionPerformed(ActionEvent evt) {
findVehicle();
}
private void findVehicle() {
List<VehicleModel> vehicles = new ArrayList<>(modelManager.getModel().getVehicleModels());
if (vehicles.isEmpty()) {
return;
}
Collections.sort(vehicles, Comparator.comparing(VehicleModel::getName));
FindVehiclePanel content = panelFactory.createFindVehiclesPanel(
vehicles,
drawingEditor.getActiveView()
);
String title = ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.FINDVEHICLE_PATH)
.getString("findVehicleAction.dialog_findVehicle.title");
ClosableDialog dialog = new ClosableDialog(dialogParent, true, content, title);
dialog.setLocationRelativeTo(dialogParent);
dialog.setVisible(true);
}
}

View File

@@ -0,0 +1,94 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.TOOLBAR_PATH;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import org.opentcs.access.KernelServicePortal;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.components.kernel.services.ServiceUnavailableException;
import org.opentcs.guing.base.model.ModelComponent;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.model.SystemModel;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.guing.common.util.ImageDirectory;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Action for pausing all vehicles.
*/
public class PauseAllVehiclesAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "openTCS.pauseAllVehicles";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(TOOLBAR_PATH);
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(PauseAllVehiclesAction.class);
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* Creates a new instance.
*
* @param modelManager Provides the current system model.
* @param portalProvider Provides access to a portal.
*/
@Inject
@SuppressWarnings("this-escape")
public PauseAllVehiclesAction(
ModelManager modelManager,
SharedKernelServicePortalProvider portalProvider
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
putValue(NAME, BUNDLE.getString("pauseAllVehiclesAction.name"));
putValue(SHORT_DESCRIPTION, BUNDLE.getString("pauseAllVehiclesAction.shortDescription"));
ImageIcon iconSmall = ImageDirectory.getImageIcon("/toolbar/pause-vehicles.16.png");
ImageIcon iconLarge = ImageDirectory.getImageIcon("/toolbar/pause-vehicles.22.png");
putValue(SMALL_ICON, iconSmall);
putValue(LARGE_ICON_KEY, iconLarge);
}
@Override
public void actionPerformed(ActionEvent evt) {
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
pauseVehicles(sharedPortal.getPortal());
}
catch (ServiceUnavailableException exc) {
LOG.warn("Could not connect to kernel", exc);
}
}
private void pauseVehicles(KernelServicePortal portal) {
ModelComponent folder = modelManager.getModel().getMainFolder(SystemModel.FolderKey.VEHICLES);
for (ModelComponent component : folder.getChildComponents()) {
VehicleModel vModel = (VehicleModel) component;
LOG.info("Pausing vehicle {}...", vModel.getVehicle().getName());
portal.getVehicleService().updateVehiclePaused(vModel.getVehicle().getReference(), true);
}
}
}

View File

@@ -0,0 +1,94 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.actions;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.TOOLBAR_PATH;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import org.opentcs.access.KernelServicePortal;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.components.kernel.services.ServiceUnavailableException;
import org.opentcs.guing.base.model.ModelComponent;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.model.SystemModel;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.guing.common.util.ImageDirectory;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Action for resuming all vehicles.
*/
public class ResumeAllVehiclesAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "openTCS.resumeAllVehicles";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(TOOLBAR_PATH);
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(ResumeAllVehiclesAction.class);
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* Creates a new instance.
*
* @param modelManager Provides the current system model.
* @param portalProvider Provides access to a portal.
*/
@Inject
@SuppressWarnings("this-escape")
public ResumeAllVehiclesAction(
ModelManager modelManager,
SharedKernelServicePortalProvider portalProvider
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
putValue(NAME, BUNDLE.getString("resumeAllVehiclesAction.name"));
putValue(SHORT_DESCRIPTION, BUNDLE.getString("resumeAllVehiclesAction.shortDescription"));
ImageIcon iconSmall = ImageDirectory.getImageIcon("/toolbar/resume-vehicles.16.png");
ImageIcon iconLarge = ImageDirectory.getImageIcon("/toolbar/resume-vehicles.22.png");
putValue(SMALL_ICON, iconSmall);
putValue(LARGE_ICON_KEY, iconLarge);
}
@Override
public void actionPerformed(ActionEvent evt) {
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
resumeVehicles(sharedPortal.getPortal());
}
catch (ServiceUnavailableException exc) {
LOG.warn("Could not connect to kernel", exc);
}
}
private void resumeVehicles(KernelServicePortal portal) {
ModelComponent folder = modelManager.getModel().getMainFolder(SystemModel.FolderKey.VEHICLES);
for (ModelComponent component : folder.getChildComponents()) {
VehicleModel vModel = (VehicleModel) component;
LOG.info("Resuming vehicle {}...", vModel.getVehicle().getName());
portal.getVehicleService().updateVehiclePaused(vModel.getVehicle().getReference(), false);
}
}
}

View File

@@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.app;
import static java.util.Objects.requireNonNull;
import static javax.swing.Action.LARGE_ICON_KEY;
import static javax.swing.Action.MNEMONIC_KEY;
import static javax.swing.Action.SMALL_ICON;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import jakarta.inject.Inject;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.common.application.ApplicationState;
import org.opentcs.guing.common.util.ImageDirectory;
import org.opentcs.operationsdesk.application.OpenTCSView;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.opentcs.util.Environment;
/**
* Displays a dialog showing information about the application.
*/
public class AboutAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "application.about";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
/**
* Stores the application's current state.
*/
private final ApplicationState appState;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* The parent component for dialogs shown by this action.
*/
private final Component dialogParent;
/**
* Creates a new instance.
*
* @param appState Stores the application's current state.
* @param portalProvider Provides access to a portal.
* @param dialogParent The parent component for dialogs shown by this action.
*/
@Inject
@SuppressWarnings("this-escape")
public AboutAction(
ApplicationState appState,
SharedKernelServicePortalProvider portalProvider,
@ApplicationFrame
Component dialogParent
) {
this.appState = requireNonNull(appState, "appState");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
this.dialogParent = requireNonNull(dialogParent, "dialogParent");
putValue(NAME, BUNDLE.getString("aboutAction.name"));
putValue(MNEMONIC_KEY, Integer.valueOf('A'));
ImageIcon icon = ImageDirectory.getImageIcon("/menu/help-contents.png");
putValue(SMALL_ICON, icon);
putValue(LARGE_ICON_KEY, icon);
}
@Override
public void actionPerformed(ActionEvent evt) {
JOptionPane.showMessageDialog(
dialogParent,
"<html><p><b>" + OpenTCSView.NAME + "</b><br> "
+ BUNDLE.getFormatted(
"aboutAction.optionPane_applicationInformation.message.baselineVersion",
Environment.getBaselineVersion()
)
+ "<br>"
+ BUNDLE.getFormatted(
"aboutAction.optionPane_applicationInformation.message.customization",
Environment.getCustomizationName(),
Environment.getCustomizationVersion()
)
+ "<br>"
+ BUNDLE.getString("aboutAction.optionPane_applicationInformation.message.copyright")
+ "<br>"
+ BUNDLE.getString("aboutAction.optionPane_applicationInformation.message.runningOn")
+ "<br>"
+ "Java: "
+ System.getProperty("java.version")
+ ", "
+ System.getProperty("java.vendor")
+ "<br>"
+ "JVM: "
+ System.getProperty("java.vm.version")
+ ", "
+ System.getProperty("java.vm.vendor")
+ "<br>"
+ "OS: "
+ System.getProperty("os.name")
+ " "
+ System.getProperty("os.version")
+ ", "
+ System.getProperty("os.arch")
+ "<br>"
+ "<b>Kernel</b><br>"
+ portalProvider.getPortalDescription()
+ "<br>"
+ BUNDLE.getFormatted(
"aboutAction.optionPane_applicationInformation.message.mode",
appState.getOperationMode()
)
+ "</p></html>",
BUNDLE.getString("aboutAction.optionPane_applicationInformation.title"),
JOptionPane.PLAIN_MESSAGE,
new ImageIcon(
getClass().getResource("/org/opentcs/guing/res/symbols/openTCS/openTCS.300x132.gif")
)
);
}
}

View File

@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JCheckBoxMenuItem;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
*/
public class FollowVehicleAction
extends
AbstractAction {
/**
* Automatically moves the drawing so a vehicle is always visible.
*/
public static final String ID = "course.vehicle.follow";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* The vehicle.
*/
private final VehicleModel vehicleModel;
/**
* The drawing editor.
*/
private final OpenTCSDrawingEditor drawingEditor;
/**
* Creates a new instance.
*
* @param vehicle The selected vehicle.
* @param drawingEditor The application's drawing editor.
*/
@Inject
@SuppressWarnings("this-escape")
public FollowVehicleAction(
@Assisted
VehicleModel vehicle,
OpenTCSDrawingEditor drawingEditor
) {
this.vehicleModel = requireNonNull(vehicle, "vehicle");
this.drawingEditor = requireNonNull(drawingEditor, "drawingEditor");
putValue(NAME, BUNDLE.getString("followVehicleAction.name"));
}
@Override
public void actionPerformed(ActionEvent evt) {
JCheckBoxMenuItem checkBox = (JCheckBoxMenuItem) evt.getSource();
OpenTCSDrawingView drawingView = drawingEditor.getActiveView();
if (drawingView != null) {
if (checkBox.isSelected()) {
drawingView.followVehicle(vehicleModel);
}
else {
drawingView.stopFollowVehicle();
}
}
}
}

View File

@@ -0,0 +1,102 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import org.opentcs.access.KernelRuntimeException;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.data.model.Vehicle;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*/
public class IntegrationLevelChangeAction
extends
AbstractAction {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(IntegrationLevelChangeAction.class);
/**
* This instance's resource bundle.
*/
private final ResourceBundleUtil bundle = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* The vehicles to change the level of.
*/
private final Collection<VehicleModel> vehicles;
/**
* Sets the level to to change the vehicles to.
*/
private final Vehicle.IntegrationLevel level;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* Creates a new instance.
*
* @param vehicles The selected vehicles.
* @param level The level to to change the vehicles to.
* @param portalProvider Provides access to a shared portal.
*/
@Inject
@SuppressWarnings("this-escape")
public IntegrationLevelChangeAction(
@Assisted
Collection<VehicleModel> vehicles,
@Assisted
Vehicle.IntegrationLevel level,
SharedKernelServicePortalProvider portalProvider
) {
this.vehicles = requireNonNull(vehicles, "vehicles");
this.level = requireNonNull(level, "level");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
String actionName;
switch (level) {
case TO_BE_NOTICED:
actionName = bundle.getString("integrationLevelChangeAction.notice.name");
break;
case TO_BE_RESPECTED:
actionName = bundle.getString("integrationLevelChangeAction.respect.name");
break;
case TO_BE_UTILIZED:
actionName = bundle.getString("integrationLevelChangeAction.utilize.name");
break;
default:
actionName = bundle.getString("integrationLevelChangeAction.ignore.name");
break;
}
putValue(NAME, actionName);
}
@Override
public void actionPerformed(ActionEvent evt) {
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
for (VehicleModel vehicle : vehicles) {
sharedPortal.getPortal().getVehicleService().updateVehicleIntegrationLevel(
vehicle.getVehicle().getReference(), level
);
}
}
catch (KernelRuntimeException e) {
LOG.warn("Unexpected exception", e);
}
}
}

View File

@@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import org.opentcs.access.KernelRuntimeException;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*/
public class PauseAction
extends
AbstractAction {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(PauseAction.class);
/**
* This instance's resource bundle.
*/
private final ResourceBundleUtil bundle = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* The vehicles to change the level of.
*/
private final Collection<VehicleModel> vehicles;
/**
* Indicates whether to pause or unpause the vehicles.
*/
private final boolean pause;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* Creates a new instance.
*
* @param vehicles The selected vehicles.
* @param pause The paused state to set the vehicles to.
* @param portalProvider Provides access to a shared portal.
*/
@Inject
@SuppressWarnings("this-escape")
public PauseAction(
@Assisted
Collection<VehicleModel> vehicles,
@Assisted
boolean pause,
SharedKernelServicePortalProvider portalProvider
) {
this.vehicles = requireNonNull(vehicles, "vehicles");
this.pause = requireNonNull(pause, "pause");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
putValue(
NAME,
pause
? bundle.getString("pauseAction.pause.name")
: bundle.getString("pauseAction.resume.name")
);
}
@Override
public void actionPerformed(ActionEvent evt) {
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
for (VehicleModel vehicle : vehicles) {
sharedPortal.getPortal().getVehicleService().updateVehiclePaused(
vehicle.getVehicle().getReference(), pause
);
}
}
catch (KernelRuntimeException e) {
LOG.warn("Unexpected exception", e);
}
}
}

View File

@@ -0,0 +1,103 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import org.opentcs.access.KernelRuntimeException;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.data.order.ReroutingType;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An action for triggering a rerouting of a selected set of vehicles.
*/
public class RerouteAction
extends
AbstractAction {
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
private static final Logger LOG = LoggerFactory.getLogger(RerouteAction.class);
private final Collection<VehicleModel> vehicles;
private final ReroutingType reroutingType;
private final SharedKernelServicePortalProvider portalProvider;
private final Component dialogParent;
/**
* Creates a new instance.
*
* @param vehicles The selected vehicles.
* @param reroutingType The selected rerouting type.
* @param portalProvider Provides access to a shared kernel service portal.
* @param dialogParent The parent component for dialogs shown by this action.
*/
@Inject
@SuppressWarnings("this-escape")
public RerouteAction(
@Assisted
Collection<VehicleModel> vehicles,
@Assisted
ReroutingType reroutingType,
SharedKernelServicePortalProvider portalProvider,
@ApplicationFrame
Component dialogParent
) {
this.vehicles = requireNonNull(vehicles, "vehicles");
this.reroutingType = requireNonNull(reroutingType, "reroutingType");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
this.dialogParent = requireNonNull(dialogParent, "dialogParent");
switch (reroutingType) {
case REGULAR:
putValue(NAME, BUNDLE.getString("rerouteAction.regularRerouting.name"));
break;
case FORCED:
putValue(NAME, BUNDLE.getString("rerouteAction.forcedRerouting.name"));
break;
default:
putValue(NAME, reroutingType.name());
}
}
@Override
public void actionPerformed(ActionEvent evt) {
if (reroutingType == ReroutingType.FORCED) {
int dialogResult = JOptionPane.showConfirmDialog(
dialogParent,
BUNDLE.getString("rerouteAction.optionPane_confirmForcedRerouting.message"),
BUNDLE.getString("rerouteAction.optionPane_confirmForcedRerouting.title"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE
);
if (dialogResult != JOptionPane.OK_OPTION) {
return;
}
}
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
for (VehicleModel vehicle : vehicles) {
sharedPortal.getPortal().getDispatcherService().reroute(
vehicle.getVehicle().getReference(),
reroutingType
);
}
}
catch (KernelRuntimeException e) {
LOG.warn("Unexpected exception", e);
}
}
}

View File

@@ -0,0 +1,77 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.jhotdraw.draw.Figure;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
*/
public class ScrollToVehicleAction
extends
AbstractAction {
/**
* Scrolls to a vehicle in the drawing.
*/
public static final String ID = "course.vehicle.scrollTo";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* The vehicle.
*/
private final VehicleModel vehicleModel;
/**
* The drawing editor.
*/
private final OpenTCSDrawingEditor drawingEditor;
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* Creates a new instance.
*
* @param vehicle The selected vehicle.
* @param drawingEditor The application's drawing editor.
* @param modelManager The model manager.
*/
@Inject
@SuppressWarnings("this-escape")
public ScrollToVehicleAction(
@Assisted
VehicleModel vehicle,
OpenTCSDrawingEditor drawingEditor,
ModelManager modelManager
) {
this.vehicleModel = requireNonNull(vehicle, "vehicle");
this.drawingEditor = requireNonNull(drawingEditor, "drawingEditor");
this.modelManager = requireNonNull(modelManager, "modelManager");
putValue(NAME, BUNDLE.getString("scrollToVehicleAction.name"));
}
@Override
public void actionPerformed(ActionEvent e) {
Figure figure = modelManager.getModel().getFigure(vehicleModel);
OpenTCSDrawingView drawingView = drawingEditor.getActiveView();
if (drawingView != null && figure != null) {
drawingView.clearSelection();
drawingView.addToSelection(figure);
drawingView.scrollTo(figure);
}
}
}

View File

@@ -0,0 +1,111 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.data.order.OrderConstants;
import org.opentcs.guing.base.model.AbstractConnectableModelComponent;
import org.opentcs.guing.base.model.elements.LocationModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.dialogs.StandardContentDialog;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.exchange.TransportOrderUtil;
import org.opentcs.operationsdesk.transport.LocationActionPanel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
*/
public class SendVehicleToLocationAction
extends
AbstractAction {
/**
* Sends a vehicle directly to a location.
*/
public static final String ID = "course.vehicle.sendToLocation";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* The vehicle.
*/
private final VehicleModel fVehicle;
/**
* The application's main frame.
*/
private final JFrame applicationFrame;
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* A helper for creating transport orders with the kernel.
*/
private final TransportOrderUtil orderUtil;
/**
* Creates a new instance.
*
* @param vehicle The selected vehicle.
* @param applicationFrame The application's main view.
* @param modelManager Provides the current system model.
* @param orderUtil A helper for creating transport orders with the kernel.
*/
@Inject
@SuppressWarnings("this-escape")
public SendVehicleToLocationAction(
@Assisted
VehicleModel vehicle,
@ApplicationFrame
JFrame applicationFrame,
ModelManager modelManager,
TransportOrderUtil orderUtil
) {
this.fVehicle = requireNonNull(vehicle, "vehicle");
this.applicationFrame = requireNonNull(applicationFrame, "applicationFrame");
this.modelManager = requireNonNull(modelManager, "modelManager");
this.orderUtil = requireNonNull(orderUtil, "orderUtil");
putValue(NAME, BUNDLE.getString("sendVehicleToLocationAction.name"));
}
@Override
public void actionPerformed(ActionEvent evt) {
List<LocationModel> locModels = locationModels();
if (!locModels.isEmpty()) {
LocationActionPanel contentPanel = new LocationActionPanel(locModels);
StandardContentDialog fDialog = new StandardContentDialog(applicationFrame, contentPanel);
fDialog.setTitle(evt.getActionCommand());
fDialog.setVisible(true);
if (fDialog.getReturnStatus() == StandardContentDialog.RET_OK) {
LocationModel location = contentPanel.getSelectedLocation();
List<AbstractConnectableModelComponent> destinationModels = new ArrayList<>();
destinationModels.add(location);
List<String> actions = new ArrayList<>();
actions.add(contentPanel.getSelectedAction());
orderUtil.createTransportOrder(
destinationModels,
actions,
System.currentTimeMillis(),
fVehicle,
OrderConstants.TYPE_NONE
);
}
}
}
private List<LocationModel> locationModels() {
return modelManager.getModel().getLocationModels();
}
}

View File

@@ -0,0 +1,99 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.base.model.elements.PointModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.dialogs.StandardContentDialog;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.exchange.TransportOrderUtil;
import org.opentcs.operationsdesk.transport.PointPanel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
*/
public class SendVehicleToPointAction
extends
AbstractAction {
/**
* Sends a vehicle directly to a point.
*/
public static final String ID = "course.vehicle.sendToPoint";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* The vehicle.
*/
private final VehicleModel vehicleModel;
/**
* The application's main frame.
*/
private final JFrame applicationFrame;
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* A helper for creating transport orders with the kernel.
*/
private final TransportOrderUtil orderUtil;
/**
* Creates a new instance.
*
* @param vehicle The selected vehicle.
* @param applicationFrame The application's main view.
* @param modelManager Provides the current system model.
* @param orderUtil A helper for creating transport orders with the kernel.
*/
@Inject
@SuppressWarnings("this-escape")
public SendVehicleToPointAction(
@Assisted
VehicleModel vehicle,
@ApplicationFrame
JFrame applicationFrame,
ModelManager modelManager,
TransportOrderUtil orderUtil
) {
this.vehicleModel = requireNonNull(vehicle, "vehicle");
this.applicationFrame = requireNonNull(applicationFrame, "applicationFrame");
this.modelManager = requireNonNull(modelManager, "modelManager");
this.orderUtil = requireNonNull(orderUtil, "orderUtil");
putValue(NAME, BUNDLE.getString("sendVehicleToPointAction.name"));
}
@Override
public void actionPerformed(ActionEvent evt) {
List<PointModel> pointModels = pointModels();
if (!pointModels.isEmpty()) {
PointPanel contentPanel = new PointPanel(pointModels);
StandardContentDialog fDialog = new StandardContentDialog(applicationFrame, contentPanel);
contentPanel.addInputValidationListener(fDialog);
fDialog.setTitle(evt.getActionCommand());
fDialog.setVisible(true);
if (fDialog.getReturnStatus() == StandardContentDialog.RET_OK) {
PointModel point = (PointModel) contentPanel.getSelectedItem();
orderUtil.createTransportOrder(point, vehicleModel);
}
}
}
private List<PointModel> pointModels() {
return modelManager.getModel().getPointModels();
}
}

View File

@@ -0,0 +1,125 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.course;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.VEHICLEPOPUP_PATH;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import org.opentcs.access.KernelRuntimeException;
import org.opentcs.access.SharedKernelServicePortal;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*/
public class WithdrawAction
extends
AbstractAction {
/**
* The ID for the 'withdraw regularly' action.
*/
public static final String ID = "course.vehicle.withdrawTransportOrder";
/**
* The ID for the 'withdraw forcibly' action.
*/
public static final String IMMEDIATELY_ID = "course.vehicle.withdrawTransportOrderImmediately";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(VEHICLEPOPUP_PATH);
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(WithdrawAction.class);
/**
* The vehicles.
*/
private final Collection<VehicleModel> vehicles;
/**
* Resource path to the correct lables.
*/
private final boolean immediateAbort;
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* The parent component for dialogs shown by this action.
*/
private final Component dialogParent;
/**
* Creates a new instance.
*
* @param vehicles The selected vehicles.
* @param immediateAbort Whether or not to abort immediately
* @param portalProvider Provides access to a shared portal.
* @param dialogParent The parent component for dialogs shown by this action.
*/
@Inject
@SuppressWarnings("this-escape")
public WithdrawAction(
@Assisted
Collection<VehicleModel> vehicles,
@Assisted
boolean immediateAbort,
SharedKernelServicePortalProvider portalProvider,
@ApplicationFrame
Component dialogParent
) {
this.vehicles = requireNonNull(vehicles, "vehicles");
this.immediateAbort = requireNonNull(immediateAbort, "immediateAbort");
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
this.dialogParent = requireNonNull(dialogParent, "dialogParent");
if (immediateAbort) {
putValue(NAME, BUNDLE.getString("withdrawAction.withdrawImmediately.name"));
}
else {
putValue(NAME, BUNDLE.getString("withdrawAction.withdraw.name"));
}
}
@Override
public void actionPerformed(ActionEvent evt) {
if (immediateAbort) {
int dialogResult
= JOptionPane.showConfirmDialog(
dialogParent,
BUNDLE.getString("withdrawAction.optionPane_confirmWithdraw.message"),
BUNDLE.getString("withdrawAction.optionPane_confirmWithdraw.title"),
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE
);
if (dialogResult != JOptionPane.OK_OPTION) {
return;
}
}
try (SharedKernelServicePortal sharedPortal = portalProvider.register()) {
for (VehicleModel vehicle : vehicles) {
sharedPortal.getPortal().getDispatcherService().withdrawByVehicle(
vehicle.getVehicle().getReference(), immediateAbort
);
}
}
catch (KernelRuntimeException e) {
LOG.warn("Unexpected exception", e);
}
}
}

View File

@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.view;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.operationsdesk.application.OpenTCSView;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action for adding new drawing views.
*/
public class AddDrawingViewAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "view.addDrawingView";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
private final OpenTCSView view;
/**
* Creates a new instance.
*
* @param view The openTCS view
*/
@SuppressWarnings("this-escape")
public AddDrawingViewAction(OpenTCSView view) {
this.view = view;
putValue(NAME, BUNDLE.getString("addDrawingViewAction.name"));
}
@Override
public void actionPerformed(ActionEvent evt) {
view.addDrawingView();
}
}

View File

@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.view;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.operationsdesk.application.OpenTCSView;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action for adding new peripheral job views.
*/
public class AddPeripheralJobViewAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "view.addPeripheralJobView";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
private final OpenTCSView view;
/**
* Creates a new instance.
*
* @param view The openTCS view
*/
@SuppressWarnings("this-escape")
public AddPeripheralJobViewAction(OpenTCSView view) {
this.view = requireNonNull(view, "view");
putValue(NAME, BUNDLE.getString("addPeripheralJobViewAction.name"));
}
@Override
public void actionPerformed(ActionEvent e) {
view.addPeripheralJobsView();
}
}

View File

@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.view;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.operationsdesk.application.OpenTCSView;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action for adding new transport order sequence views.
*/
public class AddTransportOrderSequenceViewAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "view.addOrderSequenceView";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
private final OpenTCSView view;
/**
* Creates a new instance.
*
* @param view The openTCS view
*/
@SuppressWarnings("this-escape")
public AddTransportOrderSequenceViewAction(OpenTCSView view) {
this.view = view;
putValue(NAME, BUNDLE.getString("addTransportOrderSequenceViewAction.name"));
}
@Override
public void actionPerformed(ActionEvent e) {
view.addTransportOrderSequenceView();
}
}

View File

@@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.view;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.util.I18nPlantOverviewOperating.MENU_PATH;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.operationsdesk.application.OpenTCSView;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* An action for adding new transport order views.
*/
public class AddTransportOrderViewAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "view.addTransportOrderView";
private static final ResourceBundleUtil BUNDLE = ResourceBundleUtil.getBundle(MENU_PATH);
private final OpenTCSView view;
/**
* Creates a new instance.
*
* @param view The openTCS view
*/
@SuppressWarnings("this-escape")
public AddTransportOrderViewAction(OpenTCSView view) {
this.view = requireNonNull(view, "view");
putValue(NAME, BUNDLE.getString("addTransportOrderViewAction.name"));
}
@Override
public void actionPerformed(ActionEvent e) {
view.addTransportOrderView();
}
}

View File

@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.action.view;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import org.opentcs.operationsdesk.application.OpenTCSView;
/**
* Action for resetting the docking layout.
*/
public class RestoreDockingLayoutAction
extends
AbstractAction {
/**
* This action's ID.
*/
public static final String ID = "openTCS.restoreDockingLayout";
private final OpenTCSView view;
/**
* Creates a new instance.
*
* @param view The openTCS view
*/
public RestoreDockingLayoutAction(OpenTCSView view) {
this.view = view;
}
@Override
public void actionPerformed(ActionEvent e) {
view.resetWindowArrangement();
}
}

View File

@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus;
import java.util.Collection;
import org.opentcs.guing.base.model.elements.VehicleModel;
/**
* A factory for various menus and menu items.
*/
public interface MenuFactory {
/**
* Creates a popup menu with actions for a set of vehicles.
*
* @param vehicles The vehicle models for which to create the popup menu.
* @return A popup menu with actions for the given vehicle.
*/
VehiclePopupMenu createVehiclePopupMenu(Collection<VehicleModel> vehicles);
}

View File

@@ -0,0 +1,232 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus;
import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.util.Collection;
import javax.swing.Action;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.order.ReroutingType;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.application.action.ActionFactory;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.operationsdesk.util.OperationsDeskConfiguration;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* A popup menu for actions for multiple selected vehicles.
*/
public class VehiclePopupMenu
extends
JPopupMenu {
/**
* Creates a new instance.
*
* @param modelManager Provides access to the current system model.
* @param actionFactory A factory for menu actions.
* @param configuration The application configuration.
* @param vehicles a set of all currently selected Vehicles.
*/
@Inject
@SuppressWarnings("this-escape")
public VehiclePopupMenu(
ModelManager modelManager,
ActionFactory actionFactory,
OperationsDeskConfiguration configuration,
@Assisted
Collection<VehicleModel> vehicles
) {
requireNonNull(modelManager, "modelManager");
requireNonNull(actionFactory, "actionFactory");
requireNonNull(vehicles, "vehicles");
final ResourceBundleUtil bundle
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.VEHICLEPOPUP_PATH);
VehicleModel singleVehicle = vehicles.stream().findFirst().get();
JCheckBoxMenuItem checkBoxMenuItem;
Action action;
JMenuItem mi = new JMenuItem();
mi.setEnabled(false);
if (vehicles.size() == 1) {
mi.setText(
bundle.getString("vehiclePopupMenu.menuItem_singleVehicle.text") + singleVehicle.getName()
);
}
else {
mi.setText(bundle.getString("vehiclePopupMenu.menuItem_multipleVehicles.text"));
}
add(mi);
addSeparator();
if (vehicles.size() == 1) {
action = actionFactory.createScrollToVehicleAction(singleVehicle);
add(action);
action = actionFactory.createFollowVehicleAction(singleVehicle);
JCheckBoxMenuItem followCheckBox = new JCheckBoxMenuItem();
followCheckBox.setAction(action);
followCheckBox.setSelected(singleVehicle.isViewFollows());
add(followCheckBox);
addSeparator();
}
if (vehicles.size() == 1) {
action = actionFactory.createSendVehicleToPointAction(singleVehicle);
action.setEnabled(
singleVehicle.isAvailableForOrder()
&& !modelManager.getModel().getPointModels().isEmpty()
);
add(action);
action = actionFactory.createSendVehicleToLocationAction(singleVehicle);
action.setEnabled(
singleVehicle.isAvailableForOrder()
&& !modelManager.getModel().getLocationModels().isEmpty()
);
add(action);
addSeparator();
}
JMenu pauseSubMenu = new JMenu(bundle.getString("vehiclePopupMenu.subMenu_pause.text"));
action = actionFactory.createPauseAction(vehicles, true);
checkBoxMenuItem = new JCheckBoxMenuItem(action);
checkBoxMenuItem.setSelected(allPaused(vehicles));
pauseSubMenu.add(checkBoxMenuItem);
action = actionFactory.createPauseAction(vehicles, false);
checkBoxMenuItem = new JCheckBoxMenuItem(action);
checkBoxMenuItem.setSelected(nonePaused(vehicles));
pauseSubMenu.add(checkBoxMenuItem);
add(pauseSubMenu);
addSeparator();
JMenu integrateSubMenu
= new JMenu(bundle.getString("vehiclePopupMenu.subMenu_integrate.text"));
action = actionFactory.createIntegrationLevelChangeAction(
vehicles,
Vehicle.IntegrationLevel.TO_BE_IGNORED
);
action.setEnabled(!isAnyProcessingOrder(vehicles));
checkBoxMenuItem = new JCheckBoxMenuItem(action);
checkBoxMenuItem.setSelected(
isAnyAtIntegrationLevel(
vehicles,
Vehicle.IntegrationLevel.TO_BE_IGNORED
)
);
integrateSubMenu.add(checkBoxMenuItem);
action = actionFactory.createIntegrationLevelChangeAction(
vehicles,
Vehicle.IntegrationLevel.TO_BE_NOTICED
);
action.setEnabled(!isAnyProcessingOrder(vehicles));
checkBoxMenuItem = new JCheckBoxMenuItem(action);
checkBoxMenuItem.setSelected(
isAnyAtIntegrationLevel(
vehicles,
Vehicle.IntegrationLevel.TO_BE_NOTICED
)
);
integrateSubMenu.add(checkBoxMenuItem);
action = actionFactory.createIntegrationLevelChangeAction(
vehicles,
Vehicle.IntegrationLevel.TO_BE_RESPECTED
);
checkBoxMenuItem = new JCheckBoxMenuItem(action);
checkBoxMenuItem.setSelected(
isAnyAtIntegrationLevel(vehicles, Vehicle.IntegrationLevel.TO_BE_RESPECTED)
);
integrateSubMenu.add(checkBoxMenuItem);
action = actionFactory.createIntegrationLevelChangeAction(
vehicles,
Vehicle.IntegrationLevel.TO_BE_UTILIZED
);
checkBoxMenuItem = new JCheckBoxMenuItem(action);
checkBoxMenuItem.setSelected(
isAnyAtIntegrationLevel(vehicles, Vehicle.IntegrationLevel.TO_BE_UTILIZED)
);
integrateSubMenu.add(checkBoxMenuItem);
add(integrateSubMenu);
addSeparator();
JMenu rerouteSubMenu
= new JMenu(bundle.getString("vehiclePopupMenu.subMenu_reroute.text"));
action = actionFactory.createRerouteAction(vehicles, ReroutingType.REGULAR);
action.setEnabled(isAnyProcessingOrder(vehicles));
rerouteSubMenu.add(action);
action = actionFactory.createRerouteAction(vehicles, ReroutingType.FORCED);
action.setEnabled(isAnyProcessingOrder(vehicles));
rerouteSubMenu.add(action);
add(rerouteSubMenu);
addSeparator();
JMenu withdrawSubMenu
= new JMenu(bundle.getString("vehiclePopupMenu.subMenu_withdraw.text"));
action = actionFactory.createWithdrawAction(vehicles, false);
action.setEnabled(isAnyProcessingOrder(vehicles));
withdrawSubMenu.add(action);
action = actionFactory.createWithdrawAction(vehicles, true);
action.setEnabled(configuration.allowForcedWithdrawal() && isAnyProcessingOrder(vehicles));
withdrawSubMenu.add(action);
add(withdrawSubMenu);
}
private boolean allPaused(Collection<VehicleModel> vehicles) {
return vehicles.stream().allMatch(vehicle -> isPaused(vehicle));
}
private boolean nonePaused(Collection<VehicleModel> vehicles) {
return vehicles.stream().noneMatch(vehicle -> isPaused(vehicle));
}
private boolean isAnyProcessingOrder(Collection<VehicleModel> vehicles) {
return vehicles.stream().anyMatch(vehicle -> isProcessingOrder(vehicle));
}
private boolean isPaused(VehicleModel vehicle) {
return Boolean.TRUE.equals(vehicle.getPropertyPaused().getValue());
}
private boolean isProcessingOrder(VehicleModel vehicle) {
return vehicle.getPropertyProcState().getValue() == Vehicle.ProcState.PROCESSING_ORDER
|| vehicle.getPropertyProcState().getValue() == Vehicle.ProcState.AWAITING_ORDER;
}
private boolean isAnyAtIntegrationLevel(
Collection<VehicleModel> vehicles,
Vehicle.IntegrationLevel level
) {
return vehicles.stream().anyMatch(
vehicle -> vehicle.getPropertyIntegrationLevel().getComparableValue().equals(level)
);
}
}

View File

@@ -0,0 +1,163 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus.menubar;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.event.KernelStateChangeEvent.State.LOGGED_IN;
import jakarta.inject.Inject;
import java.awt.event.ActionEvent;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.jhotdraw.draw.Figure;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.operationsdesk.application.action.ViewActionMap;
import org.opentcs.operationsdesk.application.action.actions.CreatePeripheralJobAction;
import org.opentcs.operationsdesk.application.action.actions.CreateTransportOrderAction;
import org.opentcs.operationsdesk.application.action.actions.FindVehicleAction;
import org.opentcs.operationsdesk.application.menus.MenuFactory;
import org.opentcs.operationsdesk.components.drawing.figures.VehicleFigure;
import org.opentcs.operationsdesk.event.KernelStateChangeEvent;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.operationsdesk.util.OperationsDeskConfiguration;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.opentcs.util.event.EventHandler;
import org.opentcs.util.event.EventSource;
/**
* The application's menu for run-time actions.
*/
public class ActionsMenu
extends
JMenu
implements
EventHandler {
/**
* A menu item for creating new transport orders.
*/
private final JMenuItem menuItemCreateTransportOrder;
/**
* A menu item for creating new peripheral jobs.
*/
private final JMenuItem menuItemCreatePeripheralJob;
/**
* A menu item for finding a vehicle in the driving course.
*/
private final JMenuItem menuItemFindVehicle;
/**
* A check box for ignoring the vehicles' precise positions.
*/
private final JCheckBoxMenuItem cbiIgnorePrecisePosition;
/**
* A check box for ignoring the vehicles' orientation angles.
*/
private final JCheckBoxMenuItem cbiIgnoreOrientationAngle;
/**
* Creates a new instance.
*
* @param actionMap The application's action map.
* @param drawingEditor The application's drawing editor.
* @param menuFactory A factory for menu items.
* @param appConfig The application's configuration.
*/
@Inject
@SuppressWarnings("this-escape")
public ActionsMenu(
ViewActionMap actionMap,
OpenTCSDrawingEditor drawingEditor,
MenuFactory menuFactory,
OperationsDeskConfiguration appConfig,
@ApplicationEventBus
EventSource eventSource
) {
requireNonNull(actionMap, "actionMap");
requireNonNull(drawingEditor, "drawingEditor");
requireNonNull(menuFactory, "menuFactory");
requireNonNull(appConfig, "appConfig");
requireNonNull(eventSource, "eventSource");
final ResourceBundleUtil labels
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.MENU_PATH);
this.setText(labels.getString("actionsMenu.text"));
this.setToolTipText(labels.getString("actionsMenu.tooltipText"));
this.setMnemonic('A');
// Menu item Actions -> Create Transport Order
menuItemCreateTransportOrder = new JMenuItem(actionMap.get(CreateTransportOrderAction.ID));
menuItemCreateTransportOrder.setEnabled(false);
add(menuItemCreateTransportOrder);
//Menu item Actions -> Create Peripheral Job.
menuItemCreatePeripheralJob = new JMenuItem(actionMap.get(CreatePeripheralJobAction.ID));
menuItemCreatePeripheralJob.setEnabled(false);
add(menuItemCreatePeripheralJob);
addSeparator();
// Menu item Actions -> Find Vehicle
menuItemFindVehicle = new JMenuItem(actionMap.get(FindVehicleAction.ID));
menuItemFindVehicle.setEnabled(false);
add(menuItemFindVehicle);
// Menu item Actions -> Ignore precise position
cbiIgnorePrecisePosition = new JCheckBoxMenuItem(
labels.getString("actionsMenu.menuItem_ignorePrecisePosition.text")
);
add(cbiIgnorePrecisePosition);
cbiIgnorePrecisePosition.setSelected(appConfig.ignoreVehiclePrecisePosition());
cbiIgnorePrecisePosition.addActionListener((ActionEvent e) -> {
for (Figure figure : drawingEditor.getDrawing().getChildren()) {
if (figure instanceof VehicleFigure) {
((VehicleFigure) figure).setIgnorePrecisePosition(cbiIgnorePrecisePosition.isSelected());
}
}
});
// Menu item Actions -> Ignore orientation angle
cbiIgnoreOrientationAngle = new JCheckBoxMenuItem(
labels.getString("actionsMenu.menuItem_ignorePreciseOrientation.text")
);
add(cbiIgnoreOrientationAngle);
cbiIgnoreOrientationAngle.setSelected(appConfig.ignoreVehicleOrientationAngle());
cbiIgnoreOrientationAngle.addActionListener((ActionEvent e) -> {
for (Figure figure : drawingEditor.getDrawing().getChildren()) {
if (figure instanceof VehicleFigure) {
((VehicleFigure) figure).setIgnoreOrientationAngle(
cbiIgnoreOrientationAngle.isSelected()
);
}
}
});
eventSource.subscribe(this);
}
@Override
public void onEvent(Object event) {
if (event instanceof KernelStateChangeEvent kernelStateChangeEvent) {
handleKernelStateChangeEvent(kernelStateChangeEvent);
}
}
private void handleKernelStateChangeEvent(KernelStateChangeEvent event) {
switch (event.getNewState()) {
case LOGGED_IN:
menuItemCreateTransportOrder.setEnabled(true);
menuItemCreatePeripheralJob.setEnabled(true);
menuItemFindVehicle.setEnabled(true);
break;
case DISCONNECTED:
menuItemCreateTransportOrder.setEnabled(false);
menuItemCreatePeripheralJob.setEnabled(false);
menuItemFindVehicle.setEnabled(false);
break;
default:
// Do nothing.
}
}
}

View File

@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus.menubar;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import javax.swing.JMenuBar;
/**
* The plant overview's main menu bar.
*/
public class ApplicationMenuBar
extends
JMenuBar {
private final FileMenu menuFile;
private final ActionsMenu menuActions;
private final ViewMenu menuView;
private final HelpMenu menuHelp;
/**
* Creates a new instance.
*
* @param menuFile The "File" menu.
* @param menuActions The "Actions" menu.
* @param menuView The "View" menu.
* @param menuHelp The "Help menu.
*/
@Inject
@SuppressWarnings("this-escape")
public ApplicationMenuBar(
FileMenu menuFile,
ActionsMenu menuActions,
ViewMenu menuView,
HelpMenu menuHelp
) {
requireNonNull(menuFile, "menuFile");
requireNonNull(menuActions, "menuActions");
requireNonNull(menuView, "menuView");
requireNonNull(menuHelp, "menuHelp");
this.menuFile = menuFile;
add(menuFile);
this.menuActions = menuActions;
add(menuActions);
this.menuView = menuView;
add(menuView);
this.menuHelp = menuHelp;
add(menuHelp);
}
}

View File

@@ -0,0 +1,137 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus.menubar;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.event.KernelStateChangeEvent.State.LOGGED_IN;
import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.guing.common.application.action.file.ModelPropertiesAction;
import org.opentcs.guing.common.application.action.file.SaveModelAction;
import org.opentcs.guing.common.application.action.file.SaveModelAsAction;
import org.opentcs.operationsdesk.application.action.ViewActionMap;
import org.opentcs.operationsdesk.application.action.actions.ConnectToKernelAction;
import org.opentcs.operationsdesk.application.action.actions.DisconnectFromKernelAction;
import org.opentcs.operationsdesk.event.KernelStateChangeEvent;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.opentcs.thirdparty.operationsdesk.jhotdraw.application.action.file.CloseFileAction;
import org.opentcs.util.event.EventHandler;
import org.opentcs.util.event.EventSource;
/**
* The application's "File" menu.
*/
public class FileMenu
extends
JMenu
implements
EventHandler {
/**
* A menu item for persisting the kernel's current model.
*/
private final JMenuItem menuItemSaveModel;
/**
* A menu item for persisting the kernel's current model with a new name.
*/
private final JMenuItem menuItemSaveModelAs;
/**
* A menu item for connecting to a kernel.
*/
private final JMenuItem menuItemConnect;
/**
* A menu item for disconnecting from the kernel.
*/
private final JMenuItem menuItemDisconnect;
/**
* A menu item for showing the current model's properties.
*/
private final JMenuItem menuItemModelProperties;
/**
* A menu item for closing the application.
*/
private final JMenuItem menuItemClose;
/**
* Creates a new instance.
*
* @param actionMap The application's action map.
* @param eventSource Where this instance registers for application events.
*/
@Inject
@SuppressWarnings("this-escape")
public FileMenu(
ViewActionMap actionMap,
@Nonnull
@ApplicationEventBus
EventSource eventSource
) {
requireNonNull(actionMap, "actionMap");
requireNonNull(eventSource, "eventSource");
final ResourceBundleUtil labels
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.MENU_PATH);
this.setText(labels.getString("fileMenu.text"));
this.setToolTipText(labels.getString("fileMenu.tooltipText"));
this.setMnemonic('F');
// Menu item File -> Save Model
menuItemSaveModel = new JMenuItem(actionMap.get(SaveModelAction.ID));
add(menuItemSaveModel);
// Menu item File -> Save Model As
menuItemSaveModelAs = new JMenuItem(actionMap.get(SaveModelAsAction.ID));
add(menuItemSaveModelAs);
addSeparator();
menuItemConnect = new JMenuItem(actionMap.get(ConnectToKernelAction.ID));
menuItemConnect.setEnabled(true);
add(menuItemConnect);
menuItemDisconnect = new JMenuItem(actionMap.get(DisconnectFromKernelAction.ID));
menuItemDisconnect.setEnabled(false);
add(menuItemDisconnect);
addSeparator();
menuItemModelProperties = new JMenuItem(actionMap.get(ModelPropertiesAction.ID));
add(menuItemModelProperties);
addSeparator();
// Menu item File -> Close
menuItemClose = new JMenuItem(actionMap.get(CloseFileAction.ID));
add(menuItemClose); // TODO: Nur bei "Stand-Alone" Frame
eventSource.subscribe(this);
}
@Override
public void onEvent(Object event) {
if (event instanceof KernelStateChangeEvent kernelStateChangeEvent) {
handleKernelStateChangeEvent(kernelStateChangeEvent);
}
}
private void handleKernelStateChangeEvent(KernelStateChangeEvent event) {
switch (event.getNewState()) {
case LOGGED_IN:
menuItemConnect.setEnabled(false);
menuItemDisconnect.setEnabled(true);
break;
case DISCONNECTED:
menuItemConnect.setEnabled(true);
menuItemDisconnect.setEnabled(false);
break;
default:
// Do nothing.
}
}
}

View File

@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus.menubar;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.opentcs.operationsdesk.application.action.ViewActionMap;
import org.opentcs.operationsdesk.application.action.app.AboutAction;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* The application's "Help" menu.
*/
public class HelpMenu
extends
JMenu {
/**
* A menu item for showing the application's "about" panel.
*/
private final JMenuItem menuItemAbout;
/**
* Creates a new instance.
*
* @param actionMap The application's action map.
*/
@Inject
@SuppressWarnings("this-escape")
public HelpMenu(ViewActionMap actionMap) {
requireNonNull(actionMap, "actionMap");
final ResourceBundleUtil labels
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.MENU_PATH);
this.setText(labels.getString("helpMenu.text"));
this.setToolTipText(labels.getString("helpMenu.tooltipText"));
this.setMnemonic('?');
menuItemAbout = add(actionMap.get(AboutAction.ID));
}
}

View File

@@ -0,0 +1,136 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.menus.menubar;
import static java.util.Objects.requireNonNull;
import static org.opentcs.operationsdesk.event.KernelStateChangeEvent.State.LOGGED_IN;
import jakarta.inject.Inject;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.guing.common.application.OperationMode;
import org.opentcs.guing.common.application.menus.menubar.ViewPluginPanelsMenu;
import org.opentcs.operationsdesk.application.action.ViewActionMap;
import org.opentcs.operationsdesk.application.action.view.AddDrawingViewAction;
import org.opentcs.operationsdesk.application.action.view.AddPeripheralJobViewAction;
import org.opentcs.operationsdesk.application.action.view.AddTransportOrderSequenceViewAction;
import org.opentcs.operationsdesk.application.action.view.AddTransportOrderViewAction;
import org.opentcs.operationsdesk.application.action.view.RestoreDockingLayoutAction;
import org.opentcs.operationsdesk.event.KernelStateChangeEvent;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
import org.opentcs.util.event.EventHandler;
import org.opentcs.util.event.EventSource;
/**
* The application's menu for view-related operations.
*/
public class ViewMenu
extends
JMenu
implements
EventHandler {
/**
* A menu item for adding a drawing view.
*/
private final JMenuItem menuAddDrawingView;
/**
* A menu item for adding a transport order view.
*/
private final JMenuItem menuTransportOrderView;
/**
* A menu item for adding an order sequence view.
*/
private final JMenuItem menuOrderSequenceView;
/**
* A menu item for adding a peripheral job view.
*/
private final JMenuItem menuPeripheralJobView;
/**
* A menu for showing/hiding plugin panels.
*/
private final ViewPluginPanelsMenu menuPluginPanels;
/**
* A menu item for restoring the default GUI layout.
*/
private final JMenuItem menuItemRestoreDockingLayout;
/**
* Creates a new instance.
*
* @param actionMap The application's action map.
* @param menuPluginPanels A menu for showing/hiding plugin panels.
*/
@Inject
@SuppressWarnings("this-escape")
public ViewMenu(
ViewActionMap actionMap,
ViewPluginPanelsMenu menuPluginPanels,
@ApplicationEventBus
EventSource eventSource
) {
requireNonNull(actionMap, "actionMap");
requireNonNull(menuPluginPanels, "menuPluginPanels");
final ResourceBundleUtil labels
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.MENU_PATH);
this.setText(labels.getString("viewMenu.text"));
this.setToolTipText(labels.getString("viewMenu.tooltipText"));
this.setMnemonic('V');
// Menu item View -> Add course view
menuAddDrawingView = new JMenuItem(actionMap.get(AddDrawingViewAction.ID));
add(menuAddDrawingView);
// Menu item View -> Add transport order view
menuTransportOrderView = new JMenuItem(actionMap.get(AddTransportOrderViewAction.ID));
add(menuTransportOrderView);
// Menu item View -> Add transport order sequence view
menuOrderSequenceView = new JMenuItem(actionMap.get(AddTransportOrderSequenceViewAction.ID));
add(menuOrderSequenceView);
menuPeripheralJobView = new JMenuItem(actionMap.get(AddPeripheralJobViewAction.ID));
add(menuPeripheralJobView);
addSeparator();
// Menu item View -> Plugins
this.menuPluginPanels = menuPluginPanels;
menuPluginPanels.setOperationMode(OperationMode.OPERATING);
menuPluginPanels.setEnabled(false);
add(menuPluginPanels);
// Menu item View -> Restore docking layout
menuItemRestoreDockingLayout = new JMenuItem(actionMap.get(RestoreDockingLayoutAction.ID));
menuItemRestoreDockingLayout.setText(
labels.getString("viewMenu.menuItem_restoreWindowArrangement.text")
);
add(menuItemRestoreDockingLayout);
eventSource.subscribe(this);
}
@Override
public void onEvent(Object event) {
if (event instanceof KernelStateChangeEvent kernelStateChangeEvent) {
handleKernelStateChangeEvent(kernelStateChangeEvent);
}
}
private void handleKernelStateChangeEvent(KernelStateChangeEvent event) {
switch (event.getNewState()) {
case LOGGED_IN:
menuPluginPanels.setEnabled(true);
break;
case DISCONNECTED:
menuPluginPanels.setEnabled(false);
break;
default:
// Do nothing.
}
}
}

View File

@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.toolbar;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.Action;
import javax.swing.JMenuItem;
import org.jhotdraw.draw.tool.DragTracker;
import org.jhotdraw.draw.tool.SelectAreaTracker;
import org.opentcs.guing.common.application.ApplicationState;
import org.opentcs.thirdparty.guing.common.jhotdraw.application.toolbar.AbstractMultipleSelectionTool;
/**
* The default selection tool.
*/
public class MultipleSelectionTool
extends
AbstractMultipleSelectionTool {
/**
* Creates a new instance.
*
* @param appState Stores the application's current state.
* @param selectAreaTracker The tracker to be used for area selections in the drawing.
* @param dragTracker The tracker to be used for dragging figures.
* @param drawingActions Drawing-related actions for the popup menus created by this tool.
* @param selectionActions Selection-related actions for the popup menus created by this tool.
*/
@Inject
public MultipleSelectionTool(
ApplicationState appState,
SelectAreaTracker selectAreaTracker,
DragTracker dragTracker,
@Assisted("drawingActions")
Collection<Action> drawingActions,
@Assisted("selectionActions")
Collection<Action> selectionActions
) {
super(appState, selectAreaTracker, dragTracker, drawingActions, selectionActions);
}
@Override
public List<JMenuItem> customPopupMenuItems() {
return new ArrayList<>();
}
}

View File

@@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.application.toolbar;
import com.google.inject.assistedinject.Assisted;
import java.util.Collection;
import javax.swing.Action;
/**
*/
public interface SelectionToolFactory {
MultipleSelectionTool createMultipleSelectionTool(
@Assisted("drawingActions")
Collection<Action> drawingActions,
@Assisted("selectionActions")
Collection<Action> selectionActions
);
}

View File

@@ -0,0 +1,506 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.8" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<SubComponents>
<Component class="javax.swing.JLabel" name="stationLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="stationLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/dialogs/createTransportOrder.properties" key="editDriverOrderPanel.label_location.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JComboBox" name="locationComboBox">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="locationComboBox" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="locationComboBoxActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.5" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="actionLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="actionLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/dialogs/createTransportOrder.properties" key="editDriverOrderPanel.label_action.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JComboBox" name="actionComboBox">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="actionComboBox" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.5" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
<LayoutCode>
<CodeStatement>
<CodeExpression id="1_layout">
<CodeVariable name="layout" type="4096" declaredType="java.awt.GridBagLayout"/>
<ExpressionOrigin>
<ExpressionProvider type="CodeConstructor">
<CodeConstructor class="java.awt.GridBagLayout" parameterTypes=""/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeExpression">
<CodeExpression id="1_layout"/>
</StatementProvider>
</CodeStatement>
<CodeStatement>
<CodeExpression id="1_layout"/>
<StatementProvider type="CodeField">
<CodeField name="columnWidths" class="java.awt.GridBagLayout"/>
</StatementProvider>
<Parameters>
<CodeExpression id="2">
<ExpressionOrigin>
<Value type="[I" editor="org.netbeans.modules.form.layoutsupport.delegates.GridBagLayoutSupport$IntArrayPropertyEditor">
<PropertyValue value="[0, 5, 0]"/>
</Value>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="1_layout"/>
<StatementProvider type="CodeField">
<CodeField name="rowHeights" class="java.awt.GridBagLayout"/>
</StatementProvider>
<Parameters>
<CodeExpression id="3">
<ExpressionOrigin>
<Value type="[I" editor="org.netbeans.modules.form.layoutsupport.delegates.GridBagLayoutSupport$IntArrayPropertyEditor">
<PropertyValue value="[0, 5, 0]"/>
</Value>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="4">
<ExpressionOrigin>
<ExpressionProvider type="ComponentRef">
<ComponentRef name="."/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeMethod">
<CodeMethod name="setLayout" class="java.awt.Container" parameterTypes="java.awt.LayoutManager"/>
</StatementProvider>
<Parameters>
<CodeExpression id="1_layout"/>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="5_gridBagConstraints">
<CodeVariable name="gridBagConstraints" type="20480" declaredType="java.awt.GridBagConstraints"/>
<ExpressionOrigin>
<ExpressionProvider type="CodeConstructor">
<CodeConstructor class="java.awt.GridBagConstraints" parameterTypes=""/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeExpression">
<CodeExpression id="5_gridBagConstraints"/>
</StatementProvider>
</CodeStatement>
<CodeStatement>
<CodeExpression id="5_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridx" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="6">
<ExpressionOrigin>
<Value type="int" value="0"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="5_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridy" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="7">
<ExpressionOrigin>
<Value type="int" value="0"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="5_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="anchor" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="8">
<ExpressionOrigin>
<Value type="int" value="17"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="5_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="insets" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="9">
<ExpressionOrigin>
<Value type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[0, 3, 0, 3]"/>
</Value>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="4"/>
<StatementProvider type="CodeMethod">
<CodeMethod name="add" class="java.awt.Container" parameterTypes="java.awt.Component, java.lang.Object"/>
</StatementProvider>
<Parameters>
<CodeExpression id="10_stationLabel">
<CodeVariable name="stationLabel" type="8194" declaredType="javax.swing.JLabel"/>
<ExpressionOrigin>
<ExpressionProvider type="ComponentRef">
<ComponentRef name="stationLabel"/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<CodeExpression id="5_gridBagConstraints"/>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="11_gridBagConstraints">
<CodeVariable name="gridBagConstraints"/>
<ExpressionOrigin>
<ExpressionProvider type="CodeConstructor">
<CodeConstructor class="java.awt.GridBagConstraints" parameterTypes=""/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeExpression">
<CodeExpression id="11_gridBagConstraints"/>
</StatementProvider>
</CodeStatement>
<CodeStatement>
<CodeExpression id="11_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridx" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="12">
<ExpressionOrigin>
<Value type="int" value="2"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="11_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridy" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="13">
<ExpressionOrigin>
<Value type="int" value="0"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="11_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="fill" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="14">
<ExpressionOrigin>
<Value type="int" value="2"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="11_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="anchor" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="15">
<ExpressionOrigin>
<Value type="int" value="17"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="11_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="weightx" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="16">
<ExpressionOrigin>
<Value type="double" value="0.5"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="4"/>
<StatementProvider type="CodeMethod">
<CodeMethod name="add" class="java.awt.Container" parameterTypes="java.awt.Component, java.lang.Object"/>
</StatementProvider>
<Parameters>
<CodeExpression id="17_locationComboBox">
<CodeVariable name="locationComboBox" type="8194" declaredType="javax.swing.JComboBox"/>
<ExpressionOrigin>
<ExpressionProvider type="ComponentRef">
<ComponentRef name="locationComboBox"/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<CodeExpression id="11_gridBagConstraints"/>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="18_gridBagConstraints">
<CodeVariable name="gridBagConstraints"/>
<ExpressionOrigin>
<ExpressionProvider type="CodeConstructor">
<CodeConstructor class="java.awt.GridBagConstraints" parameterTypes=""/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeExpression">
<CodeExpression id="18_gridBagConstraints"/>
</StatementProvider>
</CodeStatement>
<CodeStatement>
<CodeExpression id="18_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridx" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="19">
<ExpressionOrigin>
<Value type="int" value="0"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="18_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridy" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="20">
<ExpressionOrigin>
<Value type="int" value="2"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="18_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="anchor" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="21">
<ExpressionOrigin>
<Value type="int" value="17"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="18_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="insets" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="22">
<ExpressionOrigin>
<Value type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[0, 3, 0, 3]"/>
</Value>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="4"/>
<StatementProvider type="CodeMethod">
<CodeMethod name="add" class="java.awt.Container" parameterTypes="java.awt.Component, java.lang.Object"/>
</StatementProvider>
<Parameters>
<CodeExpression id="23_actionLabel">
<CodeVariable name="actionLabel" type="8194" declaredType="javax.swing.JLabel"/>
<ExpressionOrigin>
<ExpressionProvider type="ComponentRef">
<ComponentRef name="actionLabel"/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<CodeExpression id="18_gridBagConstraints"/>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="24_gridBagConstraints">
<CodeVariable name="gridBagConstraints"/>
<ExpressionOrigin>
<ExpressionProvider type="CodeConstructor">
<CodeConstructor class="java.awt.GridBagConstraints" parameterTypes=""/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<StatementProvider type="CodeExpression">
<CodeExpression id="24_gridBagConstraints"/>
</StatementProvider>
</CodeStatement>
<CodeStatement>
<CodeExpression id="24_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridx" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="25">
<ExpressionOrigin>
<Value type="int" value="2"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="24_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="gridy" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="26">
<ExpressionOrigin>
<Value type="int" value="2"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="24_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="fill" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="27">
<ExpressionOrigin>
<Value type="int" value="2"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="24_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="anchor" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="28">
<ExpressionOrigin>
<Value type="int" value="17"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="24_gridBagConstraints"/>
<StatementProvider type="CodeField">
<CodeField name="weightx" class="java.awt.GridBagConstraints"/>
</StatementProvider>
<Parameters>
<CodeExpression id="29">
<ExpressionOrigin>
<Value type="double" value="0.5"/>
</ExpressionOrigin>
</CodeExpression>
</Parameters>
</CodeStatement>
<CodeStatement>
<CodeExpression id="4"/>
<StatementProvider type="CodeMethod">
<CodeMethod name="add" class="java.awt.Container" parameterTypes="java.awt.Component, java.lang.Object"/>
</StatementProvider>
<Parameters>
<CodeExpression id="30_actionComboBox">
<CodeVariable name="actionComboBox" type="8194" declaredType="javax.swing.JComboBox"/>
<ExpressionOrigin>
<ExpressionProvider type="ComponentRef">
<ComponentRef name="actionComboBox"/>
</ExpressionProvider>
</ExpressionOrigin>
</CodeExpression>
<CodeExpression id="24_gridBagConstraints"/>
</Parameters>
</CodeStatement>
</LayoutCode>
</Form>

View File

@@ -0,0 +1,249 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import javax.swing.DefaultComboBoxModel;
import org.opentcs.guing.base.components.properties.type.StringSetProperty;
import org.opentcs.guing.base.model.AbstractConnectableModelComponent;
import org.opentcs.guing.base.model.elements.LocationModel;
import org.opentcs.guing.base.model.elements.LocationTypeModel;
import org.opentcs.guing.base.model.elements.PointModel;
import org.opentcs.guing.common.components.dialogs.DialogContent;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* Panel to edit a drive order.
*/
public class EditDriveOrderPanel
extends
DialogContent {
/**
* Available locations.
*/
private final List<LocationModel> fLocations;
/**
* The selected location.
*/
private AbstractConnectableModelComponent fSelectedLocation;
/**
* Selected action.
*/
private String fSelectedAction;
/**
* Creates new form EditDriveOrderPanel
*
* @param locations available locations.
*/
@SuppressWarnings("this-escape")
public EditDriveOrderPanel(List<LocationModel> locations) {
initComponents();
fLocations = sortLocations(locations);
setDialogTitle(
ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.CREATETO_PATH)
.getString("editDriverOrderPanel.create.title")
);
}
/**
* Creates new form EditDriveOrderPanel
*
* @param locations available locations.
* @param location selected location
* @param action selected action.
*/
@SuppressWarnings("this-escape")
public EditDriveOrderPanel(
List<LocationModel> locations,
AbstractConnectableModelComponent location, String action
) {
checkArgument(
location instanceof PointModel || location instanceof LocationModel,
String.format(
"Selected location has to be of type PointModel or LocationModel "
+ "and not \"%s\".", location.getClass().getName()
)
);
initComponents();
fLocations = sortLocations(locations);
fSelectedLocation = location;
fSelectedAction = action;
setDialogTitle(
ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.CREATETO_PATH)
.getString("editDriverOrderPanel.edit.title")
);
}
/**
* Sorts a list of locations based on their name.
*
* @param locations list of locations to sort.
* @return The list of sorted locations.
*/
private List<LocationModel> sortLocations(List<LocationModel> locations) {
Comparator<LocationModel> c = new Comparator<LocationModel>() {
@Override
public int compare(LocationModel o1, LocationModel o2) {
String s1 = o1.getName().toLowerCase();
String s2 = o2.getName().toLowerCase();
return s1.compareTo(s2);
}
};
List<LocationModel> result = new ArrayList<>(locations);
Collections.sort(result, c);
return result;
}
@Override
public void update() {
}
@Override
public void initFields() {
for (LocationModel s : fLocations) {
locationComboBox.addItem(s.getName());
}
if (fSelectedLocation != null) {
locationComboBox.setSelectedItem(fSelectedLocation.getName());
}
else if (locationComboBox.getItemCount() > 0) {
locationComboBox.setSelectedIndex(0);
}
if (fSelectedAction != null) {
actionComboBox.setSelectedItem(fSelectedAction);
}
}
/**
* Returns the selected location.
*
* @return The selected location
*/
public Optional<LocationModel> getSelectedLocation() {
int index = locationComboBox.getSelectedIndex();
return index == -1 ? Optional.empty() : Optional.ofNullable(fLocations.get(index));
}
/**
* Returns the selected action.
*
* @return The selected action.
*/
public Optional<String> getSelectedAction() {
return Optional.ofNullable((String) actionComboBox.getSelectedItem());
}
// FORMATTER:OFF
// CHECKSTYLE:OFF
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
stationLabel = new javax.swing.JLabel();
locationComboBox = new javax.swing.JComboBox<>();
actionLabel = new javax.swing.JLabel();
actionComboBox = new javax.swing.JComboBox<>();
java.awt.GridBagLayout layout = new java.awt.GridBagLayout();
layout.columnWidths = new int[] {0, 5, 0};
layout.rowHeights = new int[] {0, 5, 0};
setLayout(layout);
stationLabel.setFont(stationLabel.getFont());
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/org/opentcs/plantoverview/operating/dialogs/createTransportOrder"); // NOI18N
stationLabel.setText(bundle.getString("editDriverOrderPanel.label_location.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 3);
add(stationLabel, gridBagConstraints);
locationComboBox.setFont(locationComboBox.getFont());
locationComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
locationComboBoxActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 0.5;
add(locationComboBox, gridBagConstraints);
actionLabel.setFont(actionLabel.getFont());
actionLabel.setText(bundle.getString("editDriverOrderPanel.label_action.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 3);
add(actionLabel, gridBagConstraints);
actionComboBox.setFont(actionComboBox.getFont());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 0.5;
add(actionComboBox, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// CHECKSTYLE:ON
// FORMATTER:ON
/**
* Updates the contents of the ComboBox with the allowed operations.
*
* @param evt the event.
*/
private void locationComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_locationComboBoxActionPerformed
DefaultComboBoxModel<String> model
= (DefaultComboBoxModel<String>) actionComboBox.getModel();
model.removeAllElements();
getSelectedLocation().ifPresent(location -> {
LocationTypeModel type = location.getLocationType();
StringSetProperty p = type.getPropertyAllowedOperations();
for (String item : new ArrayList<>(type.getPropertyAllowedOperations().getItems())) {
model.addElement(item);
}
if (model.getSize() > 0) {
actionComboBox.setSelectedIndex(0);
}
});
}//GEN-LAST:event_locationComboBoxActionPerformed
// FORMATTER:OFF
// CHECKSTYLE:OFF
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox<String> actionComboBox;
private javax.swing.JLabel actionLabel;
private javax.swing.JComboBox<String> locationComboBox;
private javax.swing.JLabel stationLabel;
// End of variables declaration//GEN-END:variables
// CHECKSTYLE:ON
// FORMATTER:ON
}

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,45,0,0,1,8"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="labelVehicles">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="labelVehicles" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/dialogs/findVehicle.properties" key="findVehiclePanel.label_vehicles.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="comboBoxVehicles">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="comboBoxVehicles" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
<Component class="javax.swing.JButton" name="buttonFind">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="buttonFind" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/dialogs/findVehicle.properties" key="findVehiclePanel.button_find.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="buttonFindActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@@ -0,0 +1,138 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.JPanel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.components.drawing.figures.VehicleFigure;
/**
* Panel to select a Vehicle that will be searched for in the view.
*/
public class FindVehiclePanel
extends
JPanel {
/**
* The list of existing vehicles.
*/
private final List<VehicleModel> fVehicles;
/**
* The view to show the found vehicle in.
*/
private final OpenTCSDrawingView fDrawingView;
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* Creates a new instance.
*
* @param vehicles A list of existing vehicles.
* @param drawingView The view to show the found vehicle in.
* @param modelManager The model manager.
*/
@Inject
@SuppressWarnings("this-escape")
public FindVehiclePanel(
@Assisted
Collection<VehicleModel> vehicles,
@Assisted
OpenTCSDrawingView drawingView,
ModelManager modelManager
) {
fVehicles = new ArrayList<>(requireNonNull(vehicles, "vehicles"));
fDrawingView = requireNonNull(drawingView, "drawingView");
this.modelManager = requireNonNull(modelManager, "modelManager");
initComponents();
for (VehicleModel vehicle : vehicles) {
comboBoxVehicles.addItem(vehicle.getName());
}
}
/**
* Returns the selected vehicle.
*
* @return The selected vehicle.
*/
public VehicleModel getSelectedVehicle() {
int index = comboBoxVehicles.getSelectedIndex();
if (index == -1) {
return null;
}
return fVehicles.get(index);
}
// FORMATTER:OFF
// CHECKSTYLE:OFF
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
labelVehicles = new javax.swing.JLabel();
comboBoxVehicles = new javax.swing.JComboBox<>();
buttonFind = new javax.swing.JButton();
labelVehicles.setFont(labelVehicles.getFont());
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/org/opentcs/plantoverview/operating/dialogs/findVehicle"); // NOI18N
labelVehicles.setText(bundle.getString("findVehiclePanel.label_vehicles.text")); // NOI18N
add(labelVehicles);
comboBoxVehicles.setFont(comboBoxVehicles.getFont());
add(comboBoxVehicles);
buttonFind.setFont(buttonFind.getFont());
buttonFind.setText(bundle.getString("findVehiclePanel.button_find.text")); // NOI18N
buttonFind.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
buttonFindActionPerformed(evt);
}
});
add(buttonFind);
}// </editor-fold>//GEN-END:initComponents
// CHECKSTYLE:ON
// FORMATTER:ON
/**
* Starts the search for the vehicle.
*/
private void buttonFindActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonFindActionPerformed
VehicleModel vehicle = getSelectedVehicle();
if (vehicle == null) {
return;
}
VehicleFigure figure = (VehicleFigure) modelManager.getModel().getFigure(vehicle);
if (figure != null) {
fDrawingView.scrollTo(figure);
}
}//GEN-LAST:event_buttonFindActionPerformed
// FORMATTER:OFF
// CHECKSTYLE:OFF
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton buttonFind;
private javax.swing.JComboBox<String> comboBoxVehicles;
private javax.swing.JLabel labelVehicles;
// End of variables declaration//GEN-END:variables
// CHECKSTYLE:ON
// FORMATTER:ON
}

View File

@@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import java.util.Collection;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
/**
*/
public interface FindVehiclePanelFactory {
/**
* Create a {@link FindVehiclePanel} for the given vehicle models.
*
* @param vehicles The vehicle models.
* @param drawingView The drawing view.
* @return A {@link FindVehiclePanel}.
*/
FindVehiclePanel createFindVehiclesPanel(
Collection<VehicleModel> vehicles,
OpenTCSDrawingView drawingView
);
}

View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 59]"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_formBundle" type="java.lang.String" value="org/opentcs/guing/components/dialogs/VehiclesPanel"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,110,0,0,0,-86"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="statusPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="vehiclePanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="vehicleLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.modules.form.editors2.FontEditor">
<FontInfo relative="true">
<Font component="vehicleLabel" property="font" relativeSize="true" size="0"/>
</FontInfo>
</Property>
<Property name="horizontalAlignment" type="int" value="0"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="North"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="batteryPanel">
<Properties>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[20, 14]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[45, 14]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="14" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="batteryIcon">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="batteryLabel">
<Properties>
<Property name="text" type="java.lang.String" value="battery"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[45, 14]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="propertiesPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="integratedLabel">
<Properties>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/panels/vehicleView.properties" key="singleVehicleView.label_integrated.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="integratedStateLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/panels/vehicleView.properties" key="singleVehicleView.label_integratedState.no.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="vehicleStateLabel">
<Properties>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/panels/vehicleView.properties" key="singleVehicleView.label_state.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="vehicleStateValueLabel">
<Properties>
<Property name="text" type="java.lang.String" value="UNAVAILABLE"/>
<Property name="toolTipText" type="java.lang.String" value=""/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="positionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/panels/vehicleView.properties" key="singleVehicleView.label_position.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="positionValueLabel">
<Properties>
<Property name="text" type="java.lang.String" value="-"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[68, 14]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[68, 14]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[68, 14]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="destinationLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/panels/vehicleView.properties" key="singleVehicleView.label_destination.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="destinationValueLabel">
<Properties>
<Property name="text" type="java.lang.String" value="-"/>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="fillLabel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@@ -0,0 +1,523 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.util.Arrays;
import java.util.ResourceBundle;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import org.jhotdraw.draw.Figure;
import org.opentcs.data.model.Vehicle;
import org.opentcs.guing.base.components.properties.event.AttributesChangeEvent;
import org.opentcs.guing.base.components.properties.event.AttributesChangeListener;
import org.opentcs.guing.base.model.elements.PointModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.components.properties.SelectionPropertiesComponent;
import org.opentcs.guing.common.components.tree.ComponentsTreeViewManager;
import org.opentcs.guing.common.components.tree.TreeViewManager;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.application.menus.MenuFactory;
import org.opentcs.operationsdesk.components.drawing.figures.VehicleFigure;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.operationsdesk.util.VehicleCourseObjectFactory;
/**
* A single vehicle in the {@link VehiclesPanel}.
*/
public class SingleVehicleView
extends
JPanel
implements
AttributesChangeListener,
Comparable<SingleVehicleView> {
/**
* The resource bundle this component uses.
*/
private static final ResourceBundle BUNDLE
= ResourceBundle.getBundle(I18nPlantOverviewOperating.VEHICLEVIEW_PATH);
/**
* The color definition for orange.
*/
private static final Color ORANGE = new Color(0xff, 0xdd, 0x75);
/**
* The color definition for green.
*/
private static final Color GREEN = new Color(0x77, 0xdb, 0x6c);
/**
* The Vehicle to be displayed.
*/
private final VehicleModel fVehicleModel;
/**
* The tree view's manager (for selecting the vehicle when it's clicked on).
*/
private final TreeViewManager treeViewManager;
/**
* The properties component (for displaying properties of the vehicle when
* it's clicked on).
*/
private final SelectionPropertiesComponent propertiesComponent;
/**
* The drawing editor (for accessing the currently active drawing view).
*/
private final OpenTCSDrawingEditor drawingEditor;
/**
* A factory for popup menus.
*/
private final MenuFactory menuFactory;
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* Panel to draw on.
*/
private final JPanel fVehicleView;
/**
* Creates new instance.
*
* @param vehicle The vehicle to be displayed.
* @param treeViewManager The tree view's manager (for selecting the vehicle
* when it's clicked on).
* @param propertiesComponent The properties component (for displaying
* properties of the vehicle when it's clicked on).
* @param drawingEditor The drawing editor (for accessing the currently active
* drawing view).
* @param crsObjFactory A factory to create vehicle figures.
* @param menuFactory A factory for popup menus.
* @param modelManager The model manager.
*/
@Inject
@SuppressWarnings("this-escape")
public SingleVehicleView(
@Assisted
VehicleModel vehicle,
ComponentsTreeViewManager treeViewManager,
SelectionPropertiesComponent propertiesComponent,
OpenTCSDrawingEditor drawingEditor,
VehicleCourseObjectFactory crsObjFactory,
MenuFactory menuFactory,
ModelManager modelManager
) {
this.fVehicleModel = requireNonNull(vehicle, "vehicle");
this.treeViewManager = requireNonNull(treeViewManager, "treeViewManager");
this.propertiesComponent = requireNonNull(
propertiesComponent,
"propertiesComponent"
);
this.drawingEditor = requireNonNull(drawingEditor, "drawingEditor");
this.menuFactory = requireNonNull(menuFactory, "menuFactory");
this.modelManager = requireNonNull(modelManager, "modelManager");
requireNonNull(crsObjFactory, "crsObjFactory");
this.fVehicleView = new VehicleView(
fVehicleModel,
crsObjFactory.createVehicleFigure(fVehicleModel)
);
initComponents();
vehiclePanel.add(fVehicleView, BorderLayout.CENTER);
vehicle.addAttributesChangeListener(this);
vehicleLabel.setText(vehicle.getName());
updateVehicle();
}
private void showPopup(int x, int y) {
menuFactory.createVehiclePopupMenu(Arrays.asList(fVehicleModel)).show(this, x, y);
}
private void updateVehicle() {
updateVehicleIntegrationLevel();
updateVehicleState();
updateVehiclePosition();
updateEnergyLevel();
updateVehicleDestination();
revalidate();
}
private void updateVehicleDestination() {
PointModel destinationPoint = getVehicleModel().getDriveOrderDestination();
if (destinationPoint != null) {
destinationValueLabel.setText(destinationPoint.getName());
}
else {
destinationValueLabel.setText("-");
}
}
private void updateVehicleIntegrationLevel() {
Vehicle.IntegrationLevel integrationLevel
= (Vehicle.IntegrationLevel) fVehicleModel.getPropertyIntegrationLevel().getValue();
switch (integrationLevel) {
case TO_BE_IGNORED:
case TO_BE_NOTICED:
integratedStateLabel.setText(
BUNDLE.getString("singleVehicleView.label_integratedState.no.text")
);
integratedStateLabel.setOpaque(false);
break;
case TO_BE_RESPECTED:
integratedStateLabel.setText(
BUNDLE.getString("singleVehicleView.label_integratedState.partially.text")
);
integratedStateLabel.setOpaque(true);
integratedStateLabel.setBackground(ORANGE);
break;
case TO_BE_UTILIZED:
integratedStateLabel.setText(
BUNDLE.getString("singleVehicleView.label_integratedState.fully.text")
);
integratedStateLabel.setOpaque(true);
integratedStateLabel.setBackground(GREEN);
break;
default:
integratedStateLabel.setText(integrationLevel.name());
integratedStateLabel.setOpaque(false);
}
}
private void updateVehicleState() {
Vehicle.State state = (Vehicle.State) fVehicleModel.getPropertyState().getValue();
vehicleStateValueLabel.setText(state.toString());
switch (state) {
case ERROR:
case UNAVAILABLE:
case UNKNOWN:
vehicleStateValueLabel.setBackground(ORANGE);
vehicleStateValueLabel.setOpaque(true);
break;
default:
vehicleStateValueLabel.setOpaque(false);
}
}
private void updateVehiclePosition() {
positionValueLabel.setText(fVehicleModel.getPropertyPoint().getText());
}
private void updateEnergyLevel() {
batteryLabel.setText(fVehicleModel.getPropertyEnergyLevel().getValue() + " %");
Vehicle vehicle = fVehicleModel.getVehicle();
if (vehicle.isEnergyLevelCritical()) {
batteryIcon.setIcon(
new ImageIcon(
getToolkit().getImage(
getClass().getClassLoader().getResource(
"org/opentcs/guing/res/symbols/panel/battery-caution-3.png"
)
)
)
);
}
else if (vehicle.isEnergyLevelDegraded()) {
batteryIcon.setIcon(
new ImageIcon(
getToolkit().getImage(
getClass().getClassLoader().getResource(
"org/opentcs/guing/res/symbols/panel/battery-060-2.png"
)
)
)
);
}
else if (vehicle.isEnergyLevelGood()) {
batteryIcon.setIcon(
new ImageIcon(
getToolkit().getImage(
getClass().getClassLoader().getResource(
"org/opentcs/guing/res/symbols/panel/battery-100-2.png"
)
)
)
);
}
}
public VehicleModel getVehicleModel() {
return fVehicleModel;
}
@Override
public void propertiesChanged(AttributesChangeEvent e) {
updateVehicle();
}
// FORMATTER:OFF
// CHECKSTYLE:OFF
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
statusPanel = new javax.swing.JPanel();
vehiclePanel = new javax.swing.JPanel();
vehicleLabel = new javax.swing.JLabel();
batteryPanel = new javax.swing.JPanel();
batteryIcon = new javax.swing.JLabel();
batteryLabel = new javax.swing.JLabel();
propertiesPanel = new javax.swing.JPanel();
integratedLabel = new javax.swing.JLabel();
integratedStateLabel = new javax.swing.JLabel();
vehicleStateLabel = new javax.swing.JLabel();
vehicleStateValueLabel = new javax.swing.JLabel();
positionLabel = new javax.swing.JLabel();
positionValueLabel = new javax.swing.JLabel();
destinationLabel = new javax.swing.JLabel();
destinationValueLabel = new javax.swing.JLabel();
fillLabel = new javax.swing.JLabel();
setMinimumSize(new java.awt.Dimension(200, 59));
setLayout(new java.awt.GridBagLayout());
statusPanel.setLayout(new java.awt.BorderLayout());
vehiclePanel.setLayout(new java.awt.BorderLayout());
vehicleLabel.setFont(vehicleLabel.getFont());
vehicleLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
vehiclePanel.add(vehicleLabel, java.awt.BorderLayout.NORTH);
statusPanel.add(vehiclePanel, java.awt.BorderLayout.CENTER);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
add(statusPanel, gridBagConstraints);
batteryPanel.setMinimumSize(new java.awt.Dimension(20, 14));
batteryPanel.setPreferredSize(new java.awt.Dimension(45, 14));
batteryPanel.setLayout(new java.awt.GridBagLayout());
batteryPanel.add(batteryIcon, new java.awt.GridBagConstraints());
batteryLabel.setText("battery");
batteryLabel.setPreferredSize(new java.awt.Dimension(45, 14));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 0, 0);
batteryPanel.add(batteryLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(14, 0, 0, 0);
add(batteryPanel, gridBagConstraints);
propertiesPanel.setLayout(new java.awt.GridBagLayout());
integratedLabel.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/org/opentcs/plantoverview/operating/panels/vehicleView"); // NOI18N
integratedLabel.setText(bundle.getString("singleVehicleView.label_integrated.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
propertiesPanel.add(integratedLabel, gridBagConstraints);
integratedStateLabel.setText(bundle.getString("singleVehicleView.label_integratedState.no.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
propertiesPanel.add(integratedStateLabel, gridBagConstraints);
vehicleStateLabel.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
vehicleStateLabel.setText(bundle.getString("singleVehicleView.label_state.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
propertiesPanel.add(vehicleStateLabel, gridBagConstraints);
vehicleStateValueLabel.setText("UNAVAILABLE");
vehicleStateValueLabel.setToolTipText("");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
propertiesPanel.add(vehicleStateValueLabel, gridBagConstraints);
positionLabel.setText(bundle.getString("singleVehicleView.label_position.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
propertiesPanel.add(positionLabel, gridBagConstraints);
positionValueLabel.setText("-");
positionValueLabel.setMaximumSize(new java.awt.Dimension(68, 14));
positionValueLabel.setMinimumSize(new java.awt.Dimension(68, 14));
positionValueLabel.setPreferredSize(new java.awt.Dimension(68, 14));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
propertiesPanel.add(positionValueLabel, gridBagConstraints);
destinationLabel.setText(bundle.getString("singleVehicleView.label_destination.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
propertiesPanel.add(destinationLabel, gridBagConstraints);
destinationValueLabel.setText("-");
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
propertiesPanel.add(destinationValueLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
add(propertiesPanel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.weightx = 1.0;
add(fillLabel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel batteryIcon;
private javax.swing.JLabel batteryLabel;
private javax.swing.JPanel batteryPanel;
private javax.swing.JLabel destinationLabel;
private javax.swing.JLabel destinationValueLabel;
private javax.swing.JLabel fillLabel;
private javax.swing.JLabel integratedLabel;
private javax.swing.JLabel integratedStateLabel;
private javax.swing.JLabel positionLabel;
private javax.swing.JLabel positionValueLabel;
private javax.swing.JPanel propertiesPanel;
private javax.swing.JPanel statusPanel;
private javax.swing.JLabel vehicleLabel;
private javax.swing.JPanel vehiclePanel;
private javax.swing.JLabel vehicleStateLabel;
private javax.swing.JLabel vehicleStateValueLabel;
// End of variables declaration//GEN-END:variables
// CHECKSTYLE:ON
// FORMATTER:ON
@Override
public int compareTo(SingleVehicleView o) {
return fVehicleModel.getName().compareTo(o.getVehicleModel().getName());
}
private class VehicleView
extends
JPanel
implements
AttributesChangeListener {
private final VehicleFigure figure;
VehicleView(VehicleModel vehicleModel, VehicleFigure figure) {
this.figure = requireNonNull(figure, "figure");
requireNonNull(vehicleModel, "vehicleModel");
vehicleModel.addAttributesChangeListener(this);
setBackground(Color.WHITE);
Rectangle r = figure.getBounds().getBounds();
r.grow(10, 10);
setPreferredSize(new Dimension(r.width, r.height));
addMouseListener(new VehicleMouseAdapter(vehicleModel));
}
@Override
public void propertiesChanged(AttributesChangeEvent e) {
figure.propertiesChanged(e);
// Because the figure is not part of any drawing it does not automatically redraw itself.
SwingUtilities.invokeLater(() -> {
this.repaint();
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawVehicle((Graphics2D) g);
}
/**
* Draws the vehicle figure into the dialog.
*
* @param g2d The graphics context.
*/
private void drawVehicle(Graphics2D g2d) {
figure.setIgnorePrecisePosition(true);
Point2D.Double posDialog = new Point2D.Double(
fVehicleView.getWidth() / 2,
fVehicleView.getHeight() / 2
);
figure.setBounds(posDialog, null);
figure.setAngle(0.0);
figure.forcedDraw(g2d);
}
}
private class VehicleMouseAdapter
extends
MouseAdapter {
private final VehicleModel vehicleModel;
VehicleMouseAdapter(VehicleModel vehicleModel) {
this.vehicleModel = requireNonNull(vehicleModel, "vehicleModel");
}
@Override
public void mouseClicked(MouseEvent evt) {
if (evt.getButton() == MouseEvent.BUTTON1) {
treeViewManager.selectItem(vehicleModel);
propertiesComponent.setModel(vehicleModel);
}
if (evt.getClickCount() == 2) {
Figure vehicleFigure = modelManager.getModel().getFigure(vehicleModel);
drawingEditor.getActiveView().scrollTo(vehicleFigure);
}
if (evt.getButton() == MouseEvent.BUTTON3) {
showPopup(evt.getX(), evt.getY());
}
}
}
}

View File

@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import org.opentcs.guing.base.model.elements.VehicleModel;
/**
*/
public interface SingleVehicleViewFactory {
/**
* Creates a new SingleVehicleView for the given model.
*
* @param vehicleModel The vehicle model.
* @return A new SingleVehicleView for the given model.
*/
SingleVehicleView createSingleVehicleView(VehicleModel vehicleModel);
}

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<Properties>
<Property name="name" type="java.lang.String" value="VehiclesPanel" noResource="true"/>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/plantoverview/operating/panels/vehicleView.properties" key="vehiclesPanel.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value=""/>
</AccessibilityProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="0"/>
<Property name="rows" type="int" value="1"/>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollPaneVehicles">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="panelVehicles">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignFlowLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,180 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dialogs;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.util.Collection;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.JPanel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.dialogs.ModifiedFlowLayout;
import org.opentcs.guing.common.event.OperationModeChangeEvent;
import org.opentcs.guing.common.event.SystemModelTransitionEvent;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.util.event.EventHandler;
/**
* Shows every vehicle available in the system in a panel.
*/
public class VehiclesPanel
extends
JPanel
implements
EventHandler {
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* A factory for vehicle views.
*/
private final SingleVehicleViewFactory vehicleViewFactory;
/**
* The vehicle views sorted.
*/
private final SortedSet<SingleVehicleView> vehicleViews = new TreeSet<>();
/**
* Creates a new instance.
*
* @param modelManager Provides the current system model.
* @param vehicleViewFactory A factory for vehicle views.
*/
@Inject
VehiclesPanel(
ModelManager modelManager,
SingleVehicleViewFactory vehicleViewFactory
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.vehicleViewFactory = requireNonNull(
vehicleViewFactory,
"vehicleViewFactory"
);
initComponents();
setPreferredSize(new Dimension(0, 97));
setMinimumSize(new Dimension(140, 120));
panelVehicles.setLayout(new ModifiedFlowLayout(FlowLayout.LEFT, 10, 10));
}
@Override
public void onEvent(Object event) {
if (event instanceof OperationModeChangeEvent) {
handleModeChange((OperationModeChangeEvent) event);
}
if (event instanceof SystemModelTransitionEvent) {
handleSystemModelTransition((SystemModelTransitionEvent) event);
}
}
private void handleModeChange(OperationModeChangeEvent evt) {
switch (evt.getNewMode()) {
case OPERATING:
setVehicleModels(modelManager.getModel().getVehicleModels());
break;
case MODELLING:
default:
clearVehicles();
}
}
/**
* Initializes this panel with the current vehicles.
*
* @param vehicleModels The vehicle models.
*/
public void setVehicleModels(Collection<VehicleModel> vehicleModels) {
// Remove vehicles of the previous model from panel
for (SingleVehicleView vehicleView : vehicleViews) {
panelVehicles.remove(vehicleView);
}
// Remove vehicles of the previous model from list
vehicleViews.clear();
// Add vehicles of actual model to list
for (VehicleModel vehicle : vehicleModels) {
vehicleViews.add(vehicleViewFactory.createSingleVehicleView(vehicle));
}
// Add vehicles of actual model to panel, sorted by name
for (SingleVehicleView vehicleView : vehicleViews) {
panelVehicles.add(vehicleView);
}
panelVehicles.revalidate();
}
/**
* Clears the vehicles in this panel.
*/
public void clearVehicles() {
for (SingleVehicleView vehicleView : vehicleViews) {
panelVehicles.remove(vehicleView);
}
vehicleViews.clear();
repaint();
}
@Override
public void repaint() {
super.repaint();
if (vehicleViews != null) {
for (SingleVehicleView view : vehicleViews) {
view.repaint();
}
}
}
private void handleSystemModelTransition(SystemModelTransitionEvent evt) {
switch (evt.getStage()) {
case UNLOADING:
clearVehicles();
break;
case LOADED:
setVehicleModels(modelManager.getModel().getVehicleModels());
break;
default:
// Do nada.
}
}
// FORMATTER:OFF
// CHECKSTYLE:OFF
/**
* This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
scrollPaneVehicles = new javax.swing.JScrollPane();
panelVehicles = new javax.swing.JPanel();
setName("VehiclesPanel"); // NOI18N
setLayout(new java.awt.GridLayout(1, 0));
scrollPaneVehicles.setViewportView(panelVehicles);
add(scrollPaneVehicles);
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/org/opentcs/plantoverview/operating/panels/vehicleView"); // NOI18N
getAccessibleContext().setAccessibleName(bundle.getString("vehiclesPanel.title")); // NOI18N
getAccessibleContext().setAccessibleDescription("");
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel panelVehicles;
private javax.swing.JScrollPane scrollPaneVehicles;
// End of variables declaration//GEN-END:variables
// CHECKSTYLE:ON
// FORMATTER:ON
}

View File

@@ -0,0 +1,220 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.dockable;
import static java.util.Objects.requireNonNull;
import bibliothek.gui.dock.common.CControl;
import bibliothek.gui.dock.common.CGrid;
import bibliothek.gui.dock.common.DefaultSingleCDockable;
import bibliothek.gui.dock.common.group.CGroupBehavior;
import jakarta.inject.Inject;
import javax.swing.JComponent;
import javax.swing.JFrame;
import org.opentcs.customizations.plantoverview.ApplicationFrame;
import org.opentcs.guing.common.components.dockable.AbstractDockingManager;
import org.opentcs.guing.common.components.dockable.CStack;
import org.opentcs.guing.common.components.properties.SelectionPropertiesComponent;
import org.opentcs.guing.common.components.tree.BlocksTreeViewManager;
import org.opentcs.guing.common.components.tree.ComponentsTreeViewManager;
import org.opentcs.operationsdesk.components.dialogs.VehiclesPanel;
import org.opentcs.operationsdesk.components.layer.LayerGroupsPanel;
import org.opentcs.operationsdesk.components.layer.LayersPanel;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* Utility class for working with dockables.
*/
public class DockingManagerOperating
extends
AbstractDockingManager {
/**
* ID for the tab pane that contains the course, transport orders and order sequences.
*/
public static final String COURSE_TAB_PANE_ID = "course_tab_pane";
/**
* ID for the dockable that contains the VehiclePanel.
*/
public static final String VEHICLES_DOCKABLE_ID = "vehicles_dock";
/**
* ID for the tab pane that contains the components, blocks and groups.
*/
private static final String TREE_TAB_PANE_ID = "tree_tab_pane";
private static final String LAYER_TAB_PANE_ID = "layer_tab_pane";
private static final String COMPONENTS_ID = "comp_dock";
private static final String BLOCKS_ID = "block_dock";
private static final String PROPERTIES_ID = "properties_id";
private static final String STATUS_ID = "status_id";
private static final String LAYERS_ID = "layers_id";
private static final String LAYER_GROUPS_ID = "layer_groups_id";
/**
* The panel showing every vehicle available in the system.
*/
private final VehiclesPanel vehiclesPanel;
/**
* The tree view manager for components.
*/
private final ComponentsTreeViewManager componentsTreeViewManager;
/**
* The tree view manager for blocks.
*/
private final BlocksTreeViewManager blocksTreeViewManager;
/**
* The panel displaying the properties of the currently selected driving course components.
*/
private final SelectionPropertiesComponent selectionPropertiesComponent;
/**
* The panel displaying the layers in the plant model.
*/
private final LayersPanel layersPanel;
/**
* The panel displaying the layer groups in the plant model.
*/
private final LayerGroupsPanel layerGroupsPanel;
/**
* Tab pane that contains the components, blocks and groups.
*/
private CStack treeTabPane;
/**
* Tab pane that contains the course, transport orders and order sequences.
*/
private CStack courseTabPane;
/**
* Tab pane that contains layers and layer groups.
*/
private CStack layerTabPane;
/**
* Creates a new instance.
*
* @param applicationFrame The application's main frame.
* @param vehiclesPanel The panel showing every vehicle available in the system.
* @param componentsTreeViewManager The tree view manager for components.
* @param blocksTreeViewManager The tree view manager for blocks.
* @param selectionPropertiesComponent The panel displaying the properties of the currently
* selected driving course components.
* @param layersPanel The panel displaying the layers in the plant model.
* @param layerGroupsPanel The panel displaying the layer groups in the plant model.
*/
@Inject
public DockingManagerOperating(
@ApplicationFrame
JFrame applicationFrame,
VehiclesPanel vehiclesPanel,
ComponentsTreeViewManager componentsTreeViewManager,
BlocksTreeViewManager blocksTreeViewManager,
SelectionPropertiesComponent selectionPropertiesComponent,
LayersPanel layersPanel,
LayerGroupsPanel layerGroupsPanel
) {
super(new CControl(applicationFrame));
this.vehiclesPanel = requireNonNull(vehiclesPanel, "vehiclesPanel");
this.componentsTreeViewManager = requireNonNull(
componentsTreeViewManager,
"componentsTreeViewManager"
);
this.blocksTreeViewManager = requireNonNull(blocksTreeViewManager, "blocksTreeViewManager");
this.selectionPropertiesComponent = requireNonNull(
selectionPropertiesComponent,
"selectionPropertiesComponent"
);
this.layersPanel = requireNonNull(layersPanel, "layersPanel");
this.layerGroupsPanel = requireNonNull(layerGroupsPanel, "layerGroupsPanel");
}
@Override
public void reset() {
removeDockable(VEHICLES_DOCKABLE_ID);
removeDockable(BLOCKS_ID);
removeDockable(COMPONENTS_ID);
removeDockable(PROPERTIES_ID);
removeDockable(STATUS_ID);
removeDockable(LAYERS_ID);
removeDockable(LAYER_GROUPS_ID);
getCControl().removeStation(getTabPane(COURSE_TAB_PANE_ID));
getCControl().removeStation(getTabPane(TREE_TAB_PANE_ID));
getCControl().removeStation(getTabPane(LAYER_TAB_PANE_ID));
}
@Override
public void initializeDockables() {
getCControl().setGroupBehavior(CGroupBehavior.TOPMOST);
// Disable keyboard shortcuts to avoid collisions.
getCControl().putProperty(CControl.KEY_GOTO_NORMALIZED, null);
getCControl().putProperty(CControl.KEY_GOTO_EXTERNALIZED, null);
getCControl().putProperty(CControl.KEY_GOTO_MAXIMIZED, null);
getCControl().putProperty(CControl.KEY_MAXIMIZE_CHANGE, null);
ResourceBundleUtil bundle
= ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.DOCKABLE_PATH);
CGrid grid = new CGrid(getCControl());
courseTabPane = new CStack(COURSE_TAB_PANE_ID);
addTabPane(COURSE_TAB_PANE_ID, courseTabPane);
DefaultSingleCDockable vehiclesDockable
= createDockable(
VEHICLES_DOCKABLE_ID,
vehiclesPanel.getAccessibleContext().getAccessibleName(),
vehiclesPanel,
false
);
treeTabPane = new CStack(TREE_TAB_PANE_ID);
addTabPane(TREE_TAB_PANE_ID, treeTabPane);
layerTabPane = new CStack(LAYER_TAB_PANE_ID);
addTabPane(LAYER_TAB_PANE_ID, layerTabPane);
DefaultSingleCDockable treeViewDock
= createDockable(
COMPONENTS_ID,
bundle.getString("dockingManagerOperating.panel_components.title"),
(JComponent) componentsTreeViewManager.getTreeView(),
false
);
DefaultSingleCDockable treeBlocks
= createDockable(
BLOCKS_ID,
bundle.getString("dockingManagerOperating.panel_blocks.title"),
(JComponent) blocksTreeViewManager.getTreeView(),
false
);
grid.add(0, 0, 250, 400, treeTabPane);
grid.add(
0, 400, 250, 300,
createDockable(
PROPERTIES_ID,
bundle.getString("dockingManagerOperating.panel_properties.title"),
selectionPropertiesComponent,
false
)
);
DefaultSingleCDockable layersDock
= createDockable(
LAYERS_ID,
bundle.getString("dockingManagerOperating.panel_layers.title"),
layersPanel,
false
);
DefaultSingleCDockable layerGroupsDock
= createDockable(
LAYER_GROUPS_ID,
bundle.getString("dockingManagerOperating.panel_layerGroups.title"),
layerGroupsPanel,
false
);
grid.add(0, 900, 250, 300, layerTabPane);
grid.add(250, 0, 150, 500, vehiclesDockable);
grid.add(400, 0, 1000, 500, courseTabPane);
getCControl().getContentArea().deploy(grid);
// init tab panes
addTabTo(treeViewDock, TREE_TAB_PANE_ID, 0);
addTabTo(treeBlocks, TREE_TAB_PANE_ID, 1);
addTabTo(layersDock, LAYER_TAB_PANE_ID, 0);
addTabTo(layerGroupsDock, LAYER_TAB_PANE_ID, 1);
treeTabPane.getStation().setFrontDockable(treeViewDock.intern());
layerTabPane.getStation().setFrontDockable(layersDock.intern());
}
}

View File

@@ -0,0 +1,115 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import javax.swing.JToggleButton;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.application.StatusPanel;
import org.opentcs.guing.common.components.drawing.DrawingOptions;
import org.opentcs.guing.common.components.drawing.DrawingViewPlacardPanel;
import org.opentcs.guing.common.components.drawing.DrawingViewScrollPane;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.guing.common.model.SystemModel;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.exchange.TransportOrderUtil;
/**
* A factory for drawing views.
*/
public class DrawingViewFactory {
/**
* A provider for drawing views.
*/
private final Provider<OpenTCSDrawingView> drawingViewProvider;
/**
* The drawing editor.
*/
private final OpenTCSDrawingEditor drawingEditor;
/**
* The status panel to display the current mouse position in.
*/
private final StatusPanel statusPanel;
/**
* The manager keeping/providing the currently loaded model.
*/
private final ModelManager modelManager;
/**
* A helper for creating transport orders.
*/
private final TransportOrderUtil orderUtil;
/**
* The drawing options.
*/
private final DrawingOptions drawingOptions;
@Inject
public DrawingViewFactory(
Provider<OpenTCSDrawingView> drawingViewProvider,
OpenTCSDrawingEditor drawingEditor,
StatusPanel statusPanel,
ModelManager modelManager,
TransportOrderUtil orderUtil,
DrawingOptions drawingOptions
) {
this.drawingViewProvider = requireNonNull(drawingViewProvider, "drawingViewProvider");
this.drawingEditor = requireNonNull(drawingEditor, "drawingEditor");
this.statusPanel = requireNonNull(statusPanel, "statusPanel");
this.modelManager = requireNonNull(modelManager, "modelManager");
this.orderUtil = requireNonNull(orderUtil, "orderUtil");
this.drawingOptions = requireNonNull(drawingOptions, "drawingOptions");
}
/**
* Creates and returns a new drawing view along with its placard panel, both
* wrapped in a scroll pane.
*
* @param systemModel The system model.
* @param selectionToolButton The selection tool button in the tool bar.
* @param dragToolButton The drag tool button in the tool bar.
* @return A new drawing view, wrapped in a scroll pane.
*/
public DrawingViewScrollPane createDrawingView(
SystemModel systemModel,
JToggleButton selectionToolButton,
JToggleButton dragToolButton
) {
requireNonNull(systemModel, "systemModel");
requireNonNull(selectionToolButton, "selectionToolButton");
requireNonNull(dragToolButton, "dragToolButton");
OpenTCSDrawingView drawingView = drawingViewProvider.get();
drawingEditor.add(drawingView);
drawingEditor.setActiveView(drawingView);
for (VehicleModel vehicle : systemModel.getVehicleModels()) {
drawingView.displayDriveOrders(vehicle, vehicle.getDisplayDriveOrders());
}
DrawingViewPlacardPanel placardPanel = new DrawingViewPlacardPanel(drawingView, drawingOptions);
DrawingViewScrollPane scrollPane = new DrawingViewScrollPane(drawingView, placardPanel);
scrollPane.originChanged(systemModel.getDrawingMethod().getOrigin());
// --- Listens to draggings in the drawing ---
ViewDragScrollListener dragScrollListener
= new ViewDragScrollListener(
scrollPane,
placardPanel.getZoomComboBox(),
selectionToolButton,
dragToolButton,
statusPanel,
modelManager,
orderUtil
);
drawingView.addMouseListener(dragScrollListener);
drawingView.addMouseMotionListener(dragScrollListener);
drawingView.getComponent().addMouseWheelListener(dragScrollListener);
return scrollPane;
}
}

View File

@@ -0,0 +1,109 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import java.util.List;
import javax.swing.SwingUtilities;
import org.opentcs.guing.base.components.properties.event.AttributesChangeEvent;
import org.opentcs.guing.base.components.properties.event.NullAttributesChangeListener;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingEditor;
import org.opentcs.guing.common.components.drawing.OpenTCSDrawingView;
import org.opentcs.guing.common.event.SystemModelTransitionEvent;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.components.drawing.figures.NamedVehicleFigure;
import org.opentcs.operationsdesk.util.VehicleCourseObjectFactory;
/**
* The <code>DrawingEditor</code> coordinates <code>DrawingViews</code>
* and the <code>Drawing</code>.
* It also offers methods to add specific unique figures to the
* <code>Drawing</code>.
*/
public class OpenTCSDrawingEditorOperating
extends
OpenTCSDrawingEditor {
/**
* Provides the current system model.
*/
private final ModelManager modelManager;
/**
* A factory for course objects.
*/
private final VehicleCourseObjectFactory courseObjectFactory;
/**
* Creates a new instance.
*
* @param courseObjectFactory A factory for course objects.
* @param modelManager Provides the current system model.
*/
@Inject
public OpenTCSDrawingEditorOperating(
VehicleCourseObjectFactory courseObjectFactory,
ModelManager modelManager
) {
super(courseObjectFactory);
this.courseObjectFactory = requireNonNull(courseObjectFactory, "courseObjectFactory");
this.modelManager = requireNonNull(modelManager, "modelManager");
}
@Override
public void onEvent(Object event) {
if (event instanceof SystemModelTransitionEvent) {
handleSystemModelTransition((SystemModelTransitionEvent) event);
}
}
private void handleSystemModelTransition(SystemModelTransitionEvent evt) {
switch (evt.getStage()) {
case UNLOADING:
// XXX Remove vehicles?
break;
case LOADED:
setVehicles(modelManager.getModel().getVehicleModels());
// initializeOffsetFigures();
break;
default:
// Do nada.
}
}
/**
* Adds the given vehicles to the drawing.
*
* @param vehicleModels The <code>VehicleModels</code> to add.
*/
public void setVehicles(List<VehicleModel> vehicleModels) {
for (VehicleModel vehicleComp : vehicleModels) {
addVehicle(vehicleComp);
}
}
/**
* Adds a vehicle to the drawing.
*
* @param vehicleModel The vehicle model to add.
*/
public void addVehicle(VehicleModel vehicleModel) {
NamedVehicleFigure vehicleFigure
= courseObjectFactory.createNamedVehicleFigure(vehicleModel);
SwingUtilities.invokeLater(() -> getDrawing().add(vehicleFigure));
vehicleModel.addAttributesChangeListener(vehicleFigure);
modelManager.getModel().registerFigure(vehicleModel, vehicleFigure);
vehicleModel.setDisplayDriveOrders(true);
for (OpenTCSDrawingView view : getAllViews()) {
view.displayDriveOrders(vehicleModel, true);
}
vehicleFigure.propertiesChanged(
new AttributesChangeEvent(new NullAttributesChangeListener(), vehicleModel)
);
}
}

View File

@@ -0,0 +1,408 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing;
import static java.util.Objects.requireNonNull;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Set;
import javax.swing.JComboBox;
import javax.swing.JToggleButton;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import org.jhotdraw.draw.DrawingView;
import org.jhotdraw.draw.Figure;
import org.opentcs.data.model.Vehicle;
import org.opentcs.guing.base.model.elements.LayoutModel;
import org.opentcs.guing.base.model.elements.PointModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.application.StatusPanel;
import org.opentcs.guing.common.components.drawing.DrawingViewScrollPane;
import org.opentcs.guing.common.components.drawing.ZoomItem;
import org.opentcs.guing.common.components.drawing.figures.FigureConstants;
import org.opentcs.guing.common.components.drawing.figures.LabeledLocationFigure;
import org.opentcs.guing.common.components.drawing.figures.LabeledPointFigure;
import org.opentcs.guing.common.components.drawing.figures.PathConnection;
import org.opentcs.guing.common.components.drawing.figures.liner.TripleBezierLiner;
import org.opentcs.guing.common.components.drawing.figures.liner.TupelBezierLiner;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.components.drawing.figures.VehicleFigure;
import org.opentcs.operationsdesk.exchange.TransportOrderUtil;
import org.opentcs.operationsdesk.util.Cursors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A listener for dragging of the drawing view and single objects inside the
* view.
*/
public class ViewDragScrollListener
extends
MouseAdapter {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(ViewDragScrollListener.class);
/**
* The scroll pane enclosing the drawing view.
*/
private final DrawingViewScrollPane scrollPane;
/**
* The combo box for selecting the zoom level.
*/
private final JComboBox<ZoomItem> zoomComboBox;
/**
* The button for enabling object selection.
*/
private final JToggleButton selectionTool;
/**
* The button for enabling dragging.
*/
private final JToggleButton dragTool;
/**
* The status panel to display the current mouse position in.
*/
private final StatusPanel statusPanel;
/**
* The manager keeping/providing the currently loaded model.
*/
private final ModelManager modelManager;
/**
* A helper for creating transport orders.
*/
private final TransportOrderUtil orderUtil;
/**
* A default cursor for the drawing view.
*/
private final Cursor defaultCursor;
/**
* The start position of drag movements.
*/
private final Point startPoint = new Point();
/**
* Start coordinate for measuring.
* XXX Is this redundant, or is it used for something different than startPoint?
*/
private final Point2D.Double fMouseStartPoint = new Point2D.Double();
/**
* Current coordinate for measuring.
*/
private final Point2D.Double fMouseCurrentPoint = new Point2D.Double();
/**
* End coordinate for measuring.
*/
private final Point2D.Double fMouseEndPoint = new Point2D.Double();
/**
* The figure a user may have pressed on / want to drag.
*/
private Figure pressedFigure;
/**
* Creates a new instance.
*
* @param scrollPane The scroll pane enclosing the drawing view.
* @param zoomComboBox The combo box for selecting the zoom level.
* @param selectionTool The button for enabling object selection.
* @param dragTool The button for enabling dragging.
* @param statusPanel The status panel to display the current mouse position in.
* @param modelManager The manager keeping/providing the currently loaded model.
* @param orderUtil A helper for creating transport orders.
*/
public ViewDragScrollListener(
DrawingViewScrollPane scrollPane,
JComboBox<ZoomItem> zoomComboBox,
JToggleButton selectionTool,
JToggleButton dragTool,
StatusPanel statusPanel,
ModelManager modelManager,
TransportOrderUtil orderUtil
) {
this.scrollPane = requireNonNull(scrollPane, "scrollPane");
this.zoomComboBox = requireNonNull(zoomComboBox, "zoomComboBox");
this.selectionTool = requireNonNull(selectionTool, "selectionTool");
this.dragTool = requireNonNull(dragTool, "dragTool");
this.statusPanel = requireNonNull(statusPanel, "statusPanel");
this.modelManager = requireNonNull(modelManager, "modelManager");
this.orderUtil = requireNonNull(orderUtil, "orderUtil");
this.defaultCursor = scrollPane.getDrawingView().getComponent().getCursor();
}
@Override
public void mouseDragged(final MouseEvent evt) {
final DrawingView drawingView = scrollPane.getDrawingView();
if (vehicleDragged()) {
drawingView.setCursor(Cursors.getDragVehicleCursor());
}
if (!(drawingView.getComponent().getParent() instanceof JViewport)) {
return;
}
final JViewport viewport = (JViewport) drawingView.getComponent().getParent();
Point cp = SwingUtilities.convertPoint(drawingView.getComponent(), evt.getPoint(), viewport);
if (dragTool.isSelected()) {
int dx = startPoint.x - cp.x;
int dy = startPoint.y - cp.y;
Point vp = viewport.getViewPosition();
vp.translate(dx, dy);
drawingView.getComponent().scrollRectToVisible(new Rectangle(vp, viewport.getSize()));
}
else { // The selection tool is selected
viewport.revalidate();
if (isMovableFigure(pressedFigure)) {
if (!isFigureCompletelyInView(pressedFigure, viewport, drawingView)) {
// If the figure exceeds the current view, start scrolling as soon as the mouse is
// hitting the view bounds.
drawingView.getComponent().scrollRectToVisible(
new Rectangle(evt.getX(), evt.getY(), 1, 1)
);
}
fMouseCurrentPoint.setLocation(drawingView.viewToDrawing(evt.getPoint()));
showPositionStatus(false);
startPoint.setLocation(cp);
}
}
SwingUtilities.invokeLater(() -> {
Rectangle2D.Double drawingArea = drawingView.getDrawing().getDrawingArea();
scrollPane.getHorizontalRuler().setPreferredWidth((int) drawingArea.width);
scrollPane.getVerticalRuler().setPreferredHeight((int) drawingArea.height);
});
}
private boolean isMovableFigure(Figure figure) {
return (figure instanceof LabeledPointFigure)
|| (figure instanceof LabeledLocationFigure)
|| ((figure instanceof PathConnection)
&& (((PathConnection) figure).getLiner() instanceof TupelBezierLiner))
|| ((figure instanceof PathConnection)
&& (((PathConnection) figure).getLiner() instanceof TripleBezierLiner));
}
private boolean isFigureCompletelyInView(
Figure figure,
JViewport viewport,
DrawingView drawingView
) {
Rectangle viewPortBounds = viewport.getViewRect();
Rectangle figureBounds = drawingView.drawingToView(figure.getDrawingArea());
return (figureBounds.getMinX() > viewPortBounds.getMinX())
&& (figureBounds.getMinY() > viewPortBounds.getMinY())
&& (figureBounds.getMaxX() < viewPortBounds.getMaxX())
&& (figureBounds.getMaxY() < viewPortBounds.getMaxY());
}
@Override
public void mousePressed(MouseEvent evt) {
final DrawingView drawingView = scrollPane.getDrawingView();
if (dragIsSelected()) {
drawingView.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
Container c = drawingView.getComponent().getParent();
if (c instanceof JViewport) {
JViewport viewPort = (JViewport) c;
Point cp = SwingUtilities.convertPoint(drawingView.getComponent(), evt.getPoint(), viewPort);
startPoint.setLocation(cp);
}
pressedFigure = drawingView.findFigure(evt.getPoint());
fMouseCurrentPoint.setLocation(drawingView.viewToDrawing(evt.getPoint()));
fMouseStartPoint.setLocation(drawingView.viewToDrawing(evt.getPoint()));
showPositionStatus(false);
}
@Override
public void mouseReleased(MouseEvent evt) {
if (dragIsSelected()) {
return;
}
final DrawingView drawingView = scrollPane.getDrawingView();
Figure fig = drawingView.findFigure(evt.getPoint());
if (fig instanceof LabeledPointFigure) {
createPossibleTransportOrder((LabeledPointFigure) fig, drawingView.getSelectedFigures());
}
pressedFigure = null;
fMouseEndPoint.setLocation(drawingView.viewToDrawing(evt.getPoint()));
if (evt.getButton() != 2) {
showPositionStatus(true);
}
else {
showPositionStatus(false);
}
}
@Override
public void mouseExited(MouseEvent evt) {
dragIsSelected();
clearPositionStatus();
}
@Override
public void mouseEntered(MouseEvent evt) {
dragIsSelected();
}
@Override
public void mouseMoved(MouseEvent evt) {
final DrawingView drawingView = scrollPane.getDrawingView();
fMouseCurrentPoint.setLocation(drawingView.viewToDrawing(evt.getPoint()));
showPositionStatus(false);
}
@Override
public void mouseClicked(MouseEvent evt) {
if (evt.getButton() == 2) {
if (dragTool.isSelected()) {
selectionTool.setSelected(true);
}
else if (selectionTool.isSelected()) {
dragTool.setSelected(true);
}
// Sets the correct cursor
dragIsSelected();
}
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.isControlDown()) {
int zoomLevel = zoomComboBox.getSelectedIndex();
int notches = e.getWheelRotation();
if (zoomLevel != -1) {
if (notches < 0) {
if (zoomLevel > 0) {
zoomLevel--;
zoomComboBox.setSelectedIndex(zoomLevel);
}
}
else {
if (zoomLevel < zoomComboBox.getItemCount() - 1) {
zoomLevel++;
zoomComboBox.setSelectedIndex(zoomLevel);
}
}
}
}
}
/**
* Checks whether the drag tool is selected.
*
* @return true if the drag tool is selected, false otherwise.
*/
private boolean dragIsSelected() {
final DrawingView drawingView = scrollPane.getDrawingView();
if (!selectionTool.isSelected() && dragTool.isSelected()) {
drawingView.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
return true;
}
else if (selectionTool.isSelected() && !dragTool.isSelected()) {
drawingView.setCursor(defaultCursor);
return false;
}
else {
return false;
}
}
/**
* Clears the mouse position information in the status panel.
*/
private void clearPositionStatus() {
statusPanel.setPositionText("");
}
/**
* Displays the current mouse position or covered area in the status panel.
*
* @param showCoveredArea Whether to display the dimensions of the covered
* area instead of the current mouse coordinates.
*/
private void showPositionStatus(boolean showCoveredArea) {
double x = fMouseCurrentPoint.x;
double y = -fMouseCurrentPoint.y;
if (showCoveredArea) {
double w = Math.abs(fMouseEndPoint.x - fMouseStartPoint.x);
double h = Math.abs(fMouseEndPoint.y - fMouseStartPoint.y);
statusPanel.setPositionText(
String.format("X %.0f Y %.0f W %.0f H %.0f", x, y, w, h)
);
}
else {
LayoutModel layout = modelManager.getModel().getLayoutModel();
double scaleX = (double) layout.getPropertyScaleX().getValue();
double scaleY = (double) layout.getPropertyScaleY().getValue();
double xmm = x * scaleX;
double ymm = y * scaleY;
statusPanel.setPositionText(
String.format("X %.0f (%.0fmm) Y %.0f (%.0fmm)", x, xmm, y, ymm)
);
}
}
/**
* Creates a transport order, assuming a single vehicle was selected before.
*
* @param figure A point figure.
*/
private void createPossibleTransportOrder(
LabeledPointFigure figure,
Set<Figure> selectedFigures
) {
if (selectedFigures.size() != 1) {
LOG.debug("More than one figure selected, skipping.");
return;
}
Figure nextFigure = selectedFigures.iterator().next();
if (!(nextFigure instanceof VehicleFigure)) {
LOG.debug("Selected figure is not a VehicleFigure, skipping.");
return;
}
PointModel model = figure.getPresentationFigure().getModel();
VehicleModel vehicleModel = (VehicleModel) nextFigure.get(FigureConstants.MODEL);
if (vehicleModel == null) {
LOG.warn("Selected VehicleFigure does not have a model, skipping.");
return;
}
if ((Vehicle.ProcState) vehicleModel.getPropertyProcState()
.getValue() != Vehicle.ProcState.IDLE) {
LOG.debug("Selected vehicle already has an order, skipping.");
return;
}
orderUtil.createTransportOrder(model, vehicleModel);
}
/**
* Returns if a vehicle is currently being dragged.
*
* @return True if yes, false otherwise.
*/
private boolean vehicleDragged() {
Set<Figure> selectedFigures = scrollPane.getDrawingView().getSelectedFigures();
if (selectedFigures.size() != 1) {
return false;
}
return selectedFigures.iterator().next() instanceof VehicleFigure;
}
}

View File

@@ -0,0 +1,116 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing.figures;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.SwingUtilities;
import org.jhotdraw.draw.Figure;
import org.opentcs.components.plantoverview.VehicleTheme;
import org.opentcs.data.model.Triple;
import org.opentcs.guing.base.model.elements.PointModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.application.ApplicationState;
import org.opentcs.guing.common.components.drawing.figures.FigureOrdinals;
import org.opentcs.guing.common.components.drawing.figures.ToolTipTextGenerator;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.application.menus.MenuFactory;
import org.opentcs.operationsdesk.util.OperationsDeskConfiguration;
/**
* A vehicle figure that adds the name of the vehicle into the image.
*/
public class NamedVehicleFigure
extends
VehicleFigure {
@Inject
public NamedVehicleFigure(
VehicleTheme vehicleTheme,
MenuFactory menuFactory,
OperationsDeskConfiguration appConfig,
@Assisted
VehicleModel model,
ToolTipTextGenerator textGenerator,
ModelManager modelManager,
ApplicationState applicationState
) {
super(
vehicleTheme,
menuFactory,
appConfig,
model,
textGenerator,
modelManager,
applicationState
);
}
@Override
protected void drawFill(Graphics2D g2d) {
super.drawFill(g2d);
g2d.setFont(getVehicleTheme().labelFont());
g2d.setPaint(getVehicleTheme().labelColor());
g2d.drawString(
getVehicleTheme().label(getModel().getVehicle()),
(int) displayBox().getCenterX() + getVehicleTheme().labelOffsetX(),
(int) displayBox().getCenterY() + getVehicleTheme().labelOffsetY()
);
}
@Override
protected void updateFigureDetails(VehicleModel model) {
super.updateFigureDetails(model);
PointModel point = model.getPoint();
Triple precisePosition = model.getPrecisePosition();
if (point == null && precisePosition == null) {
// If neither the point nor the precise position is known, don't draw the figure.
SwingUtilities.invokeLater(() -> setVisible(false));
}
else if (precisePosition != null && !isIgnorePrecisePosition()) {
// If a precise position exists, it is set in setBounds(), so it doesn't need any coordinates.
SwingUtilities.invokeLater(() -> {
setVisible(true);
setBounds(new Point2D.Double(), null);
});
setFigureDetailsChanged(true);
}
else if (point != null) {
SwingUtilities.invokeLater(() -> {
setVisible(true);
Figure pointFigure = getModelManager().getModel().getFigure(point);
Rectangle2D.Double r = pointFigure.getBounds();
Point2D.Double pCenter = new Point2D.Double(r.getCenterX(), r.getCenterY());
// Draw figure in the center of the node.
// Angle is set in setBounds().
setBounds(pCenter, null);
});
setFigureDetailsChanged(true);
}
else {
SwingUtilities.invokeLater(() -> setVisible(false));
}
}
@Override
public boolean isVisible() {
if (getModel().getPoint() == null) {
return super.isVisible();
}
return super.isVisible()
&& getModelManager().getModel().getFigure(getModel().getPoint()).isVisible();
}
@Override
public int getLayer() {
return FigureOrdinals.VEHICLE_FIGURE_ORDINAL;
}
}

View File

@@ -0,0 +1,207 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing.figures;
import static java.util.Objects.requireNonNull;
import static org.opentcs.data.model.Vehicle.State.ERROR;
import static org.opentcs.data.model.Vehicle.State.UNAVAILABLE;
import static org.opentcs.data.model.Vehicle.State.UNKNOWN;
import jakarta.inject.Inject;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.stream.Collectors;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.peripherals.PeripheralJob;
import org.opentcs.guing.base.AllocationState;
import org.opentcs.guing.base.model.FigureDecorationDetails;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.figures.ToolTipTextGenerator;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.peripherals.jobs.PeripheralJobsContainer;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
import org.opentcs.thirdparty.guing.common.jhotdraw.util.ResourceBundleUtil;
/**
* A tool tip generator integrating information about a vehicle's state.
*/
public class ToolTipTextGeneratorOperationsDesk
extends
ToolTipTextGenerator {
/**
* A unicode play symbol.
*/
private static final String PLAY_SYMBOL = "\u23f5";
/**
* A unicode hourglass symbol.
*/
private static final String HOURGLASS_SYMBOL = "\u29d6";
/**
* Collection of peripheral jobs.
*/
private final PeripheralJobsContainer peripheralJobContainer;
/**
* Creates a new instance.
*
* @param modelManager The model manager to use.
* @param peripheralJobContainer The peripheral job container to use.
*/
@Inject
public ToolTipTextGeneratorOperationsDesk(
ModelManager modelManager,
PeripheralJobsContainer peripheralJobContainer
) {
super(modelManager);
this.peripheralJobContainer = requireNonNull(peripheralJobContainer, "peripheralJobContainer");
}
@Override
public String getToolTipText(VehicleModel model) {
requireNonNull(model, "model");
StringBuilder sb = new StringBuilder("<html>\n");
sb.append(model.getDescription())
.append(" ")
.append("<b>")
.append(model.getName())
.append("</b>\n");
appendVehicleState(sb, model);
appendMiscProps(sb, model);
appendPeripheralInformationVehicle(sb, model);
sb.append("</html>\n");
return sb.toString();
}
@Override
protected void appendAllocatingVehicle(StringBuilder sb, FigureDecorationDetails figure) {
List<Entry<VehicleModel, AllocationState>> allocationStates = figure.getAllocationStates()
.entrySet()
.stream()
.filter(entry -> entry.getValue() == AllocationState.ALLOCATED)
.collect(Collectors.toList());
if (allocationStates.isEmpty()) {
return;
}
sb.append("<hr>\n");
allocationStates
.forEach(entry -> {
sb.append(getResourceAllocatedByText())
.append(" ")
.append(entry.getKey().getName())
.append("<br>");
});
}
private void appendPeripheralInformationVehicle(StringBuilder sb, VehicleModel vehicle) {
sb.append("<hr>\n");
sb.append(getRelatedPeripheralJobHeadingText()).append('\n');
sb.append("<ul>\n");
peripheralJobContainer.getPeripheralJobs().stream()
.filter(job -> !job.getState().isFinalState())
.filter(job -> job.getPeripheralOperation().isCompletionRequired())
.filter(job -> Objects.equals(job.getRelatedVehicle(), vehicle.getVehicle().getReference()))
.sorted(Comparator.comparing(PeripheralJob::getCreationTime))
.forEach(job -> appendPeripheralJobListItem(sb, job));
sb.append("</ul>\n");
}
@SuppressWarnings("checkstyle:LineLength")
private String getRelatedPeripheralJobHeadingText() {
return ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.MISC_PATH)
.getString(
"toolTipTextGeneratorOperationsDesk.vehicleModel.awaitPeripheralJobCompletion.text"
);
}
private void appendPeripheralJobListItem(StringBuilder sb, PeripheralJob job) {
sb.append("<li>")
.append(
job.getState() == PeripheralJob.State.BEING_PROCESSED
? PLAY_SYMBOL
: HOURGLASS_SYMBOL
)
.append(job.getPeripheralOperation().getLocation().getName())
.append(": ")
.append(job.getPeripheralOperation().getOperation())
.append(" (")
.append(job.getName())
.append(")</li>\n");
}
private void appendVehicleState(StringBuilder sb, VehicleModel model) {
sb.append("<hr>\n");
sb.append(model.getPropertyPoint().getDescription()).append(": ")
.append(model.getPoint() != null ? model.getPoint().getName() : "?")
.append('\n');
sb.append("<br>\n");
sb.append(model.getPropertyNextPoint().getDescription()).append(": ")
.append(model.getNextPoint() != null ? model.getNextPoint().getName() : "?")
.append('\n');
sb.append("<br>\n");
sb.append(model.getPropertyState().getDescription())
.append(": <font color=").append(stateColorString(model.getVehicle())).append(">")
.append(model.getPropertyState().getValue())
.append("</font>\n");
sb.append("<br>\n");
sb.append(model.getPropertyProcState().getDescription()).append(": ")
.append(model.getPropertyProcState().getValue())
.append('\n');
sb.append("<br>\n");
sb.append(model.getPropertyIntegrationLevel().getDescription()).append(": ")
.append(model.getPropertyIntegrationLevel().getValue())
.append('\n');
sb.append("<br>\n");
sb.append(model.getPropertyEnergyLevel().getDescription())
.append(": <font color=").append(energyColorString(model.getVehicle())).append(">")
.append(model.getPropertyEnergyLevel().getValue())
.append("%</font>\n");
}
private String energyColorString(Vehicle vehicle) {
if (vehicle.isEnergyLevelCritical()) {
return "red";
}
else if (vehicle.isEnergyLevelDegraded()) {
return "orange";
}
else if (vehicle.isEnergyLevelGood()) {
return "green";
}
else {
return "black";
}
}
private String stateColorString(Vehicle vehicle) {
switch (vehicle.getState()) {
case ERROR:
return "red";
case UNAVAILABLE:
case UNKNOWN:
return "orange";
default:
return "black";
}
}
@SuppressWarnings("checkstyle:LineLength")
private String getResourceAllocatedByText() {
return ResourceBundleUtil.getBundle(I18nPlantOverviewOperating.MISC_PATH)
.getString(
"toolTipTextGeneratorOperationsDesk.figureDecorationDetails.resourceAllocatedBy.text"
);
}
}

View File

@@ -0,0 +1,537 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing.figures;
import static java.awt.image.ImageObserver.ABORT;
import static java.awt.image.ImageObserver.ALLBITS;
import static java.awt.image.ImageObserver.FRAMEBITS;
import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import javax.swing.SwingUtilities;
import org.jhotdraw.draw.DrawingView;
import org.jhotdraw.draw.Figure;
import org.jhotdraw.draw.handle.Handle;
import org.jhotdraw.geom.BezierPath;
import org.opentcs.components.plantoverview.VehicleTheme;
import org.opentcs.data.model.Triple;
import org.opentcs.data.order.TransportOrder;
import org.opentcs.guing.base.components.properties.event.AttributesChangeEvent;
import org.opentcs.guing.base.components.properties.event.AttributesChangeListener;
import org.opentcs.guing.base.components.properties.type.AngleProperty;
import org.opentcs.guing.base.model.elements.AbstractConnection;
import org.opentcs.guing.base.model.elements.PathModel;
import org.opentcs.guing.base.model.elements.PointModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.application.ApplicationState;
import org.opentcs.guing.common.components.drawing.ZoomPoint;
import org.opentcs.guing.common.components.drawing.course.Origin;
import org.opentcs.guing.common.components.drawing.figures.FigureConstants;
import org.opentcs.guing.common.components.drawing.figures.LabeledPointFigure;
import org.opentcs.guing.common.components.drawing.figures.PathConnection;
import org.opentcs.guing.common.components.drawing.figures.PointFigure;
import org.opentcs.guing.common.components.drawing.figures.TCSFigure;
import org.opentcs.guing.common.components.drawing.figures.ToolTipTextGenerator;
import org.opentcs.guing.common.components.drawing.figures.liner.TripleBezierLiner;
import org.opentcs.guing.common.components.drawing.figures.liner.TupelBezierLiner;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.application.menus.MenuFactory;
import org.opentcs.operationsdesk.application.menus.VehiclePopupMenu;
import org.opentcs.operationsdesk.components.dialogs.SingleVehicleView;
import org.opentcs.operationsdesk.components.drawing.figures.decoration.VehicleOutlineHandle;
import org.opentcs.operationsdesk.util.OperationsDeskConfiguration;
/**
* The graphical representation of a vehicle.
*/
public class VehicleFigure
extends
TCSFigure
implements
AttributesChangeListener,
ImageObserver {
/**
* When the position of the vehicle changed.
*/
public static final String POSITION_CHANGED = "position_changed";
/**
* The figure's length in drawing units.
*/
private static final double LENGTH = 30.0;
/**
* The figure's width in drawing units.
*/
private static final double WIDTH = 20.0;
/**
* The vehicle theme to be used.
*/
private final VehicleTheme vehicleTheme;
/**
* A factory for popup menus.
*/
private final MenuFactory menuFactory;
/**
* The tool tip text generator.
*/
private final ToolTipTextGenerator textGenerator;
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* The application's current state.
*/
private final ApplicationState applicationState;
/**
* The angle at which the image is to be drawn.
*/
private double fAngle;
/**
* The image.
*/
private transient Image fImage;
/**
* Whether to ignore the vehicle's precise position or not.
*/
private boolean ignorePrecisePosition;
/**
* Whether to ignore the vehicle's orientation angle or not.
*/
private boolean ignoreOrientationAngle;
/**
* Indicates whether figure details changed.
*/
private boolean figureDetailsChanged;
/**
* Creates a new instance.
*
* @param vehicleTheme The vehicle theme to be used.
* @param menuFactory A factory for popup menus.
* @param appConfig The application's configuration.
* @param model The model corresponding to this graphical object.
* @param textGenerator The tool tip text generator.
* @param modelManager The model manager.
* @param applicationState The application's current state.
*/
@Inject
@SuppressWarnings("this-escape")
public VehicleFigure(
VehicleTheme vehicleTheme,
MenuFactory menuFactory,
OperationsDeskConfiguration appConfig,
@Assisted
VehicleModel model,
ToolTipTextGenerator textGenerator,
ModelManager modelManager,
ApplicationState applicationState
) {
super(model);
this.vehicleTheme = requireNonNull(vehicleTheme, "vehicleTheme");
this.menuFactory = requireNonNull(menuFactory, "menuFactory");
this.textGenerator = requireNonNull(textGenerator, "textGenerator");
this.modelManager = requireNonNull(modelManager, "modelManager");
this.applicationState = requireNonNull(applicationState, "applicationState");
fDisplayBox = new Rectangle((int) LENGTH, (int) WIDTH);
fZoomPoint = new ZoomPoint(0.5 * LENGTH, 0.5 * WIDTH);
setIgnorePrecisePosition(appConfig.ignoreVehiclePrecisePosition());
setIgnoreOrientationAngle(appConfig.ignoreVehicleOrientationAngle());
fImage = vehicleTheme.statelessImage(model.getVehicle());
}
@Override
public VehicleModel getModel() {
return (VehicleModel) get(FigureConstants.MODEL);
}
public void setAngle(double angle) {
fAngle = angle;
}
public double getAngle() {
return fAngle;
}
@Override
public Rectangle2D.Double getBounds() {
Rectangle2D.Double r2d = new Rectangle2D.Double();
r2d.setRect(fDisplayBox.getBounds2D());
return r2d;
}
@Override
public Object getTransformRestoreData() {
return fDisplayBox.clone();
}
@Override
public void restoreTransformTo(Object restoreData) {
Rectangle r = (Rectangle) restoreData;
fDisplayBox.x = r.x;
fDisplayBox.y = r.y;
fDisplayBox.width = r.width;
fDisplayBox.height = r.height;
fZoomPoint.setX(r.getCenterX());
fZoomPoint.setY(r.getCenterY());
}
@Override
public void transform(AffineTransform tx) {
Point2D center = fZoomPoint.getPixelLocationExactly();
setBounds((Point2D.Double) tx.transform(center, center), null);
}
@Override
public String getToolTipText(Point2D.Double p) {
return textGenerator.getToolTipText(getModel());
}
/**
* Sets the ignore flag for the vehicle's reported orientation angle.
*
* @param doIgnore Whether to ignore the reported orientation angle.
*/
public final void setIgnoreOrientationAngle(boolean doIgnore) {
ignoreOrientationAngle = doIgnore;
PointModel point = getModel().getPoint();
if (point == null) {
// Only draw the vehicle if the point is known or the precise position is to be used.
setVisible(!ignorePrecisePosition);
}
else {
Figure pointFigure = modelManager.getModel().getFigure(point);
Rectangle2D.Double r = pointFigure.getBounds();
Point2D.Double pCenter = new Point2D.Double(r.getCenterX(), r.getCenterY());
setBounds(pCenter, null);
fireFigureChanged();
}
}
/**
* Sets the ignore flag for the vehicle's precise position.
*
* @param doIgnore Whether to ignore the reported precise position of the
* vehicle.
*/
public final void setIgnorePrecisePosition(boolean doIgnore) {
ignorePrecisePosition = doIgnore;
PointModel point = getModel().getPoint();
if (point == null) {
// Only draw the vehicle if the point is known or the precise position is to be used.
setVisible(!ignorePrecisePosition);
}
else {
Figure pointFigure = modelManager.getModel().getFigure(point);
Rectangle2D.Double r = pointFigure.getBounds();
Point2D.Double pCenter = new Point2D.Double(r.getCenterX(), r.getCenterY());
setBounds(pCenter, null);
fireFigureChanged();
}
}
/**
* Draws the center of the figure at <code>anchor</code>; the size does not
* change.
*
* @param anchor Center of the figure
* @param lead Not used
*/
@Override
public void setBounds(Point2D.Double anchor, Point2D.Double lead) {
VehicleModel model = getModel();
Rectangle2D.Double oldBounds = getBounds();
setVisible(false);
Triple precisePosition = model.getPrecisePosition();
if (!ignorePrecisePosition) {
if (precisePosition != null) {
setVisible(true);
Origin origin = modelManager.getModel().getDrawingMethod().getOrigin();
if (origin.getScaleX() != 0.0 && origin.getScaleY() != 0.0) {
anchor.x = precisePosition.getX() / origin.getScaleX();
anchor.y = -precisePosition.getY() / origin.getScaleY();
}
}
}
fZoomPoint.setX(anchor.x);
fZoomPoint.setY(anchor.y);
fDisplayBox.x = (int) (anchor.x - 0.5 * LENGTH);
fDisplayBox.y = (int) (anchor.y - 0.5 * WIDTH);
firePropertyChange(POSITION_CHANGED, oldBounds, getBounds());
updateVehicleOrientation();
}
private void updateVehicleOrientation() {
VehicleModel model = getModel();
// orientation:
// 1. Use exact orientation from vehicle adapter.
// 2. Use orientation from current point.
// 3. Use direction to next point.
// 4. Use last known orientation.
double angle = model.getOrientationAngle();
PointModel currentPoint = model.getPoint();
if (currentPoint != null) {
setVisible(true);
}
if (!Double.isNaN(angle) && !ignoreOrientationAngle) {
fAngle = angle;
}
else if (currentPoint != null) {
// Use orientation from current point.
AngleProperty ap = currentPoint.getPropertyVehicleOrientationAngle();
angle = (double) ap.getValue();
if (!Double.isNaN(angle)) {
fAngle = angle;
}
else {
alignVehicleToNextPoint();
}
}
}
private void alignVehicleToNextPoint() {
VehicleModel model = getModel();
PointModel nextPoint = model.getNextPoint();
PointModel currentPoint = model.getPoint();
AbstractConnection connection;
if (model.getDriveOrderState() == TransportOrder.State.BEING_PROCESSED) {
connection = model.getCurrentDriveOrderPath();
}
else {
if (nextPoint != null) {
connection = currentPoint.getConnectionTo(nextPoint);
}
else {
// No destination point, use a random point connected to the current point.
connection = currentPoint.getConnections().stream()
.filter(con -> con instanceof PathModel)
.filter(con -> Objects.equals(con.getStartComponent(), currentPoint))
.findFirst()
.orElse(null);
}
}
if (connection != null) {
fAngle = calculateAngle(connection);
}
}
private double calculateAngle(AbstractConnection connection) {
PointModel currentPoint = (PointModel) connection.getStartComponent();
PointModel nextPoint = (PointModel) connection.getEndComponent();
PathConnection pathFigure
= (PathConnection) modelManager.getModel().getFigure(connection);
LabeledPointFigure clpf
= (LabeledPointFigure) modelManager.getModel().getFigure(currentPoint);
PointFigure cpf = clpf.getPresentationFigure();
if (pathFigure.getLiner() instanceof TupelBezierLiner
|| pathFigure.getLiner() instanceof TripleBezierLiner) {
BezierPath bezierPath = pathFigure.getBezierPath();
Point2D.Double cp = bezierPath.get(0, BezierPath.C2_MASK);
double dx = cp.getX() - cpf.getZoomPoint().getX();
double dy = cp.getY() - cpf.getZoomPoint().getY();
return Math.toDegrees(Math.atan2(-dy, dx));
}
else {
LabeledPointFigure nlpf
= (LabeledPointFigure) modelManager.getModel().getFigure(nextPoint);
PointFigure npf = nlpf.getPresentationFigure();
double dx = npf.getZoomPoint().getX() - cpf.getZoomPoint().getX();
double dy = npf.getZoomPoint().getY() - cpf.getZoomPoint().getY();
return Math.toDegrees(Math.atan2(-dy, dx));
}
}
/**
* Forces the vehicle figure to be drawn. (Used primarily for {@link SingleVehicleView}.)
*
* @param g2d The graphics context.
*/
public void forcedDraw(Graphics2D g2d) {
drawFill(g2d);
}
@Override
protected void drawFigure(Graphics2D g2d) {
VehicleModel model = getModel();
PointModel currentPoint = model.getPoint();
Triple precisePosition = model.getPrecisePosition();
if (currentPoint != null || precisePosition != null) {
drawFill(g2d);
}
}
@Override
protected void drawFill(Graphics2D g2d) {
if (g2d == null) {
return;
}
int dx;
int dy;
Rectangle r = displayBox();
if (fImage != null) {
dx = (r.width - fImage.getWidth(this)) / 2;
dy = (r.height - fImage.getHeight(this)) / 2;
int x = r.x + dx;
int y = r.y + dy;
AffineTransform oldAF = g2d.getTransform();
g2d.translate(r.getCenterX(), r.getCenterY());
g2d.rotate(-Math.toRadians(fAngle));
g2d.translate(-r.getCenterX(), -r.getCenterY());
g2d.drawImage(fImage, x, y, null);
g2d.setTransform(oldAF);
}
else {
// TODO: Draw an outline, e.g. a rectangle.
}
}
@Override
protected void drawStroke(Graphics2D g2d) {
// Nothing to do here - Vehicle Figure is completely drawn in drawFill()
}
@Override
public Collection<Handle> createHandles(int detailLevel) {
Collection<Handle> handles = new ArrayList<>();
switch (detailLevel) {
case -1: // Mouse Moved
handles.add(new VehicleOutlineHandle(this));
break;
case 0: // Mouse clicked
// handles.add(new VehicleOutlineHandle(this));
break;
case 1: // Double-Click
// handles.add(new VehicleOutlineHandle(this));
break;
default:
break;
}
return handles;
}
@Override
public boolean handleMouseClick(
Point2D.Double p,
MouseEvent evt,
DrawingView drawingView
) {
// This gets executed on a double click AND a right click on the figure
VehicleModel model = getModel();
VehiclePopupMenu menu = menuFactory.createVehiclePopupMenu(Arrays.asList(model));
menu.show(drawingView.getComponent(), evt.getX(), evt.getY());
return false;
}
@Override
public void propertiesChanged(AttributesChangeEvent e) {
if (e.getInitiator().equals(this)
|| e.getModel() == null) {
return;
}
updateFigureDetails((VehicleModel) e.getModel());
if (isFigureDetailsChanged()) {
SwingUtilities.invokeLater(() -> {
// Only call if the figure is visible - will cause NPE in BoundsOutlineHandle otherwise.
if (isVisible()) {
fireFigureChanged();
}
});
setFigureDetailsChanged(false);
}
}
/**
* Updates the figure details based on the given vehicle model.
* <p>
* If figure details do change, call {@link #setFigureDetailsChanged(boolean)} to set the
* corresponding flag to {@code true}.
* When overriding this method, always remember to call the super-implementation.
* </p>
*
* @param model The updated vehicle model.
*/
protected void updateFigureDetails(VehicleModel model) {
fImage = getVehicleTheme().statefulImage(model.getVehicle());
setFigureDetailsChanged(true);
}
@Override
public boolean imageUpdate(
Image img, int infoflags,
int x, int y,
int width, int height
) {
if ((infoflags & (FRAMEBITS | ALLBITS)) != 0) {
invalidate();
}
return (infoflags & (ALLBITS | ABORT)) == 0;
}
/**
* Returns the vehicle theme.
*
* @return The vehicle theme.
*/
protected VehicleTheme getVehicleTheme() {
return vehicleTheme;
}
public boolean isFigureDetailsChanged() {
return figureDetailsChanged;
}
public void setFigureDetailsChanged(boolean figureDetailsChanged) {
this.figureDetailsChanged = figureDetailsChanged;
}
public boolean isIgnorePrecisePosition() {
return ignorePrecisePosition;
}
public ModelManager getModelManager() {
return modelManager;
}
}

View File

@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing.figures;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.figures.FigureFactory;
/**
*/
public interface VehicleFigureFactory
extends
FigureFactory {
VehicleFigure createVehicleFigure(VehicleModel model);
NamedVehicleFigure createNamedVehicleFigure(VehicleModel model);
}

View File

@@ -0,0 +1,76 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing.figures;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import org.jhotdraw.draw.event.FigureEvent;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.components.drawing.figures.LabeledFigure;
import org.opentcs.guing.common.components.drawing.figures.TCSFigure;
import org.opentcs.guing.common.components.drawing.figures.TCSLabelFigure;
/**
*/
public class VehicleLabelFigure
extends
TCSLabelFigure {
private static final Color COLOR_BACKGROUND = new Color(0xFFFFF0); // beige
private static final int MARGIN = 4;
public VehicleLabelFigure(String vehicleName) {
super(vehicleName);
}
@Override
protected void drawFill(Graphics2D g) {
if (getText() != null) {
TextLayout layout = getTextLayout();
Rectangle2D bounds = layout.getBounds();
RoundRectangle2D.Double rr = new RoundRectangle2D.Double(
bounds.getX() + origin.x - MARGIN,
bounds.getY() + origin.y + layout.getAscent() - MARGIN,
bounds.getWidth() + 2 * MARGIN,
bounds.getHeight() + 2 + MARGIN,
MARGIN, MARGIN
);
g.setPaint(COLOR_BACKGROUND);
g.fill(rr);
}
}
@Override
protected void drawStroke(Graphics2D g) {
}
@Override
protected void drawText(Graphics2D g) {
if (getText() != null || isEditable()) {
TextLayout layout = getTextLayout();
g.setPaint(Color.BLUE.darker());
layout.draw(g, (float) origin.x, (float) (origin.y + layout.getAscent()));
}
}
@Override
public void figureChanged(FigureEvent event) {
if (event.getFigure() instanceof LabeledFigure) {
LabeledFigure lf = (LabeledFigure) event.getFigure();
TCSFigure figure = lf.getPresentationFigure();
VehicleModel model = (VehicleModel) figure.getModel();
String name = model.getName();
if (model.getPoint() != null) {
name += "@" + model.getPoint().getName();
}
setText(name);
invalidate();
validate();
}
}
}

View File

@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.drawing.figures.decoration;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import org.jhotdraw.draw.Figure;
import org.jhotdraw.draw.handle.BoundsOutlineHandle;
import org.opentcs.operationsdesk.components.drawing.figures.VehicleFigure;
/**
*/
public class VehicleOutlineHandle
extends
BoundsOutlineHandle {
public VehicleOutlineHandle(Figure owner) {
super(owner);
}
@Override
public void draw(Graphics2D g) {
VehicleFigure vf = (VehicleFigure) getOwner();
Rectangle2D bounds = vf.getBounds();
if (view != null) {
AffineTransform at = view.getDrawingToViewTransform();
at.translate(bounds.getCenterX(), bounds.getCenterY());
at.rotate(-Math.toRadians(vf.getAngle()));
at.translate(-bounds.getCenterX(), -bounds.getCenterY());
Path2D shape = (Path2D) at.createTransformedShape(bounds);
g.setClip(shape);
g.setStroke(new BasicStroke(2.0f));
g.draw(shape);
Color c = new Color(127, 0, 127, 127);
g.setPaint(c);
g.fill(shape);
}
}
}

View File

@@ -0,0 +1,97 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.layer;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import java.awt.BorderLayout;
import java.util.Arrays;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.table.TableRowSorter;
import org.opentcs.guing.common.components.layer.LayerGroupEditor;
import org.opentcs.guing.common.components.layer.LayerGroupManager;
import org.opentcs.guing.common.persistence.ModelManager;
/**
* A panel to display and edit layer groups.
*/
public class LayerGroupsPanel
extends
JPanel {
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* The layer manager.
*/
private final LayerGroupManager layerGroupManager;
/**
* The layer editor.
*/
private final LayerGroupEditor layerGroupEditor;
/**
* The table to display available layers.
*/
private JTable table;
/**
* The table model.
*/
private LayerGroupsTableModel tableModel;
@Inject
@SuppressWarnings("this-escape")
public LayerGroupsPanel(
ModelManager modelManager,
LayerGroupManager layerGroupManager,
LayerGroupEditor layerGroupEditor
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.layerGroupManager = requireNonNull(layerGroupManager, "layerGroupManager");
this.layerGroupEditor = requireNonNull(layerGroupEditor, "layerGroupEditor");
initComponents();
}
private void initComponents() {
setLayout(new BorderLayout());
tableModel = new LayerGroupsTableModel(modelManager, layerGroupEditor);
layerGroupManager.addLayerGroupChangeListener(tableModel);
table = new JTable(tableModel);
initTable();
add(new JScrollPane(table), BorderLayout.CENTER);
}
private void initTable() {
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
TableRowSorter<LayerGroupsTableModel> sorter = new TableRowSorter<>(tableModel);
// Sort the table by the layer ordinals...
sorter.setSortKeys(
Arrays.asList(
new RowSorter.SortKey(LayerGroupsTableModel.COLUMN_ID, SortOrder.DESCENDING)
)
);
// ...but prevent manual sorting.
for (int i = 0; i < table.getColumnCount(); i++) {
sorter.setSortable(i, false);
}
sorter.setSortsOnUpdates(true);
table.setRowSorter(sorter);
// Hide the column that shows the layer group IDs.
table.removeColumn(
table.getColumnModel()
.getColumn(table.convertColumnIndexToView(LayerGroupsTableModel.COLUMN_ID))
);
}
}

View File

@@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.layer;
import javax.swing.SwingUtilities;
import org.opentcs.guing.common.components.layer.AbstractLayerGroupsTableModel;
import org.opentcs.guing.common.components.layer.LayerGroupEditor;
import org.opentcs.guing.common.persistence.ModelManager;
/**
* The table model for layer groups for the Operations Desk application.
*/
class LayerGroupsTableModel
extends
AbstractLayerGroupsTableModel {
/**
* Creates a new instance.
*
* @param modelManager The model manager.
* @param layerGroupEditor The layer group editor.
*/
LayerGroupsTableModel(ModelManager modelManager, LayerGroupEditor layerGroupEditor) {
super(modelManager, layerGroupEditor);
}
@Override
protected boolean isNameColumnEditable() {
return false;
}
@Override
protected boolean isVisibleColumnEditable() {
return true;
}
@Override
public void groupsInitialized() {
// Once the layers are initialized we want to redraw the entire table to avoid any
// display errors.
executeOnEventDispatcherThread(() -> fireTableDataChanged());
}
@Override
public void groupsChanged() {
// Update the entire table but don't use fireTableDataChanged() to preserve the current
// selection.
executeOnEventDispatcherThread(() -> fireTableRowsUpdated(0, getRowCount() - 1));
}
@Override
public void groupAdded() {
}
@Override
public void groupRemoved() {
}
/**
* Ensures the given runnable is executed on the EDT.
* If the runnable is already being called on the EDT, the runnable is executed immediately.
* Otherwise it is scheduled for execution on the EDT.
* <p>
* Note: Deferring a runnable by scheduling it for execution on the EDT even though it would
* have already been executed on the EDT may lead to exceptions due to data inconsistency.
* </p>
*
* @param runnable The runnable.
*/
private void executeOnEventDispatcherThread(Runnable runnable) {
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
}
else {
SwingUtilities.invokeLater(runnable);
}
}
}

View File

@@ -0,0 +1,115 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.layer;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import java.awt.BorderLayout;
import java.util.Arrays;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.table.TableRowSorter;
import org.opentcs.guing.common.components.layer.DisabledCheckBoxCellRenderer;
import org.opentcs.guing.common.components.layer.LayerEditor;
import org.opentcs.guing.common.components.layer.LayerGroupCellRenderer;
import org.opentcs.guing.common.components.layer.LayerGroupManager;
import org.opentcs.guing.common.components.layer.LayerManager;
import org.opentcs.guing.common.persistence.ModelManager;
/**
* A panel to display and edit layers.
*/
public class LayersPanel
extends
JPanel {
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* The layer manager.
*/
private final LayerManager layerManager;
/**
* The layer group manager.
*/
private final LayerGroupManager layerGroupManager;
/**
* The layer editor.
*/
private final LayerEditor layerEditor;
/**
* The table to display available layers.
*/
private JTable table;
/**
* The table model.
*/
private LayersTableModel tableModel;
@Inject
@SuppressWarnings("this-escape")
public LayersPanel(
ModelManager modelManager,
LayerManager layerManager,
LayerGroupManager layerGroupManager,
LayerEditor layerEditor
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.layerManager = requireNonNull(layerManager, "layerManager");
this.layerGroupManager = requireNonNull(layerGroupManager, "layerGroupManager");
this.layerEditor = requireNonNull(layerEditor, "layerEditor");
initComponents();
}
private void initComponents() {
setLayout(new BorderLayout());
tableModel = new LayersTableModel(modelManager, layerEditor);
layerManager.setLayerChangeListener(tableModel);
layerGroupManager.addLayerGroupChangeListener(tableModel);
table = new JTable(tableModel);
initTable();
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
}
private void initTable() {
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
TableRowSorter<LayersTableModel> sorter = new TableRowSorter<>(tableModel);
// Sort the table by the layer ordinals...
sorter.setSortKeys(
Arrays.asList(
new RowSorter.SortKey(LayersTableModel.COLUMN_ORDINAL, SortOrder.DESCENDING)
)
);
// ...but prevent manual sorting.
for (int i = 0; i < table.getColumnCount(); i++) {
sorter.setSortable(i, false);
}
sorter.setSortsOnUpdates(true);
table.setRowSorter(sorter);
// Hide the column that shows the layer ordinals.
table.removeColumn(
table.getColumnModel()
.getColumn(table.convertColumnIndexToView(LayersTableModel.COLUMN_ORDINAL))
);
table.getColumnModel()
.getColumn(table.convertColumnIndexToView(LayersTableModel.COLUMN_GROUP))
.setCellRenderer(new LayerGroupCellRenderer());
table.getColumnModel()
.getColumn(table.convertColumnIndexToView(LayersTableModel.COLUMN_GROUP_VISIBLE))
.setCellRenderer(new DisabledCheckBoxCellRenderer());
}
}

View File

@@ -0,0 +1,266 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.layer;
import static java.util.Objects.requireNonNull;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import org.opentcs.data.model.visualization.Layer;
import org.opentcs.data.model.visualization.LayerGroup;
import org.opentcs.guing.base.components.layer.LayerWrapper;
import org.opentcs.guing.common.components.layer.LayerChangeListener;
import org.opentcs.guing.common.components.layer.LayerEditor;
import org.opentcs.guing.common.components.layer.LayerGroupChangeListener;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.util.I18nPlantOverviewOperating;
/**
* A table model for layers.
*/
class LayersTableModel
extends
AbstractTableModel
implements
LayerChangeListener,
LayerGroupChangeListener {
/**
* The number of the "Ordinal" column.
*/
public static final int COLUMN_ORDINAL = 0;
/**
* The number of the "Visible" column.
*/
public static final int COLUMN_VISIBLE = 1;
/**
* The number of the "Name" column.
*/
public static final int COLUMN_NAME = 2;
/**
* The number of the "Group" column.
*/
public static final int COLUMN_GROUP = 3;
/**
* The number of the "Group visible" column.
*/
public static final int COLUMN_GROUP_VISIBLE = 4;
/**
* The resource bundle to use.
*/
private static final ResourceBundle BUNDLE
= ResourceBundle.getBundle(I18nPlantOverviewOperating.LAYERS_PATH);
/**
* The column names.
*/
private static final String[] COLUMN_NAMES = new String[]{
BUNDLE.getString("layersTableModel.column_ordinal.headerText"),
BUNDLE.getString("layersTableModel.column_visible.headerText"),
BUNDLE.getString("layersTableModel.column_name.headerText"),
BUNDLE.getString("layersTableModel.column_group.headerText"),
BUNDLE.getString("layersTableModel.column_groupVisible.headerText")
};
/**
* The column classes.
*/
private static final Class<?>[] COLUMN_CLASSES = new Class<?>[]{
Integer.class,
Boolean.class,
String.class,
LayerGroup.class,
Boolean.class
};
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* The layer editor.
*/
private final LayerEditor layerEditor;
/**
* Creates a new instance.
*
* @param modelManager The model manager.
* @param layerEditor The layer editor.
*/
LayersTableModel(
ModelManager modelManager,
LayerEditor layerEditor
) {
this.modelManager = requireNonNull(modelManager, "modelManager");
this.layerEditor = requireNonNull(layerEditor, "layerEditor");
}
@Override
public int getRowCount() {
return getLayers().size();
}
@Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (rowIndex < 0 || rowIndex >= getRowCount()) {
return null;
}
Layer entry = getLayers().get(rowIndex);
switch (columnIndex) {
case COLUMN_ORDINAL:
return entry.getOrdinal();
case COLUMN_VISIBLE:
return entry.isVisible();
case COLUMN_NAME:
return entry.getName();
case COLUMN_GROUP:
return getLayerGroups().get(entry.getGroupId());
case COLUMN_GROUP_VISIBLE:
return getLayerGroups().get(entry.getGroupId()).isVisible();
default:
throw new IllegalArgumentException("Invalid column index: " + columnIndex);
}
}
@Override
public String getColumnName(int columnIndex) {
return COLUMN_NAMES[columnIndex];
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return COLUMN_CLASSES[columnIndex];
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
switch (columnIndex) {
case COLUMN_ORDINAL:
return false;
case COLUMN_VISIBLE:
return true;
case COLUMN_NAME:
return false;
case COLUMN_GROUP:
return false;
case COLUMN_GROUP_VISIBLE:
return false;
default:
throw new IllegalArgumentException("Invalid column index: " + columnIndex);
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (rowIndex < 0 || rowIndex >= getRowCount()) {
return;
}
if (aValue == null) {
return;
}
Layer entry = getLayers().get(rowIndex);
switch (columnIndex) {
case COLUMN_ORDINAL:
// Do nothing.
break;
case COLUMN_VISIBLE:
layerEditor.setLayerVisible(entry.getId(), (boolean) aValue);
break;
case COLUMN_NAME:
// Do nothing.
break;
case COLUMN_GROUP:
// Do nothing.
break;
case COLUMN_GROUP_VISIBLE:
// Do nothing.
break;
default:
throw new IllegalArgumentException("Invalid column index: " + columnIndex);
}
}
@Override
public void layersInitialized() {
// Once the layers are initialized we want to redraw the entire table to avoid any
// display errors.
executeOnEventDispatcherThread(() -> fireTableDataChanged());
}
@Override
public void layersChanged() {
// Update the entire table but don't use fireTableDataChanged() to preserve the current
// selection.
executeOnEventDispatcherThread(() -> fireTableRowsUpdated(0, getRowCount() - 1));
}
@Override
public void layerAdded() {
}
@Override
public void layerRemoved() {
}
@Override
public void groupsInitialized() {
}
@Override
public void groupsChanged() {
// The visibility of a group, which we display as well, may have changed. Update the table.
executeOnEventDispatcherThread(() -> fireTableRowsUpdated(0, getRowCount() - 1));
}
@Override
public void groupAdded() {
}
@Override
public void groupRemoved() {
}
private List<Layer> getLayers() {
return getLayerWrappers().values().stream()
.map(wrapper -> wrapper.getLayer())
.collect(Collectors.toList());
}
private Map<Integer, LayerWrapper> getLayerWrappers() {
return modelManager.getModel().getLayoutModel().getPropertyLayerWrappers().getValue();
}
private Map<Integer, LayerGroup> getLayerGroups() {
return modelManager.getModel().getLayoutModel().getPropertyLayerGroups().getValue();
}
/**
* Ensures the given runnable is executed on the EDT.
* If the runnable is already being called on the EDT, the runnable is executed immediately.
* Otherwise it is scheduled for execution on the EDT.
* <p>
* Note: Deferring a runnable by scheduling it for execution on the EDT even though it would
* have already been executed on the EDT may lead to exceptions due to data inconsistency.
* </p>
*
* @param runnable The runnable.
*/
private void executeOnEventDispatcherThread(Runnable runnable) {
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
}
else {
SwingUtilities.invokeLater(runnable);
}
}
}

View File

@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.components.tree.elements;
import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import javax.swing.JPopupMenu;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.application.GuiManager;
import org.opentcs.guing.common.components.tree.elements.VehicleUserObject;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.application.menus.MenuFactory;
/**
* A Vehicle in the tree view.
*/
public class VehicleUserObjectOperating
extends
VehicleUserObject {
/**
* A factory for popup menus.
*/
private final MenuFactory menuFactory;
/**
* Creates a new instance.
*
* @param model The corresponding vehicle object.
* @param guiManager The gui manager.
* @param modelManager Provides the current system model.
* @param menuFactory A factory for popup menus.
*/
@Inject
public VehicleUserObjectOperating(
@Assisted
VehicleModel model,
GuiManager guiManager,
ModelManager modelManager,
MenuFactory menuFactory
) {
super(model, guiManager, modelManager);
this.menuFactory = requireNonNull(menuFactory, "menuFactory");
}
@Override
public JPopupMenu getPopupMenu() {
return menuFactory.createVehiclePopupMenu(selectedVehicles);
}
}

View File

@@ -0,0 +1,88 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.event;
import static java.util.Objects.requireNonNull;
import java.util.EventObject;
import org.opentcs.access.Kernel;
/**
* Informs listeners about a change of the kernel's state.
*/
public class KernelStateChangeEvent
extends
EventObject {
/**
* The new/current kernel state.
*/
private final State newState;
/**
* Creates a new instance.
*
* @param source The source of this event.
* @param newState The new/current kernel state.
*/
public KernelStateChangeEvent(Object source, State newState) {
super(source);
this.newState = requireNonNull(newState, "newState");
}
/**
* Returns the new/current kernel state.
*
* @return The new/current kernel state.
*/
public State getNewState() {
return newState;
}
@Override
public String toString() {
return "KernelStateChangeEvent{"
+ "newState=" + newState
+ ", source=" + getSource()
+ '}';
}
public static State convertKernelState(Kernel.State kernelState) {
switch (kernelState) {
case MODELLING:
return State.MODELLING;
case OPERATING:
return State.OPERATING;
case SHUTDOWN:
return State.SHUTDOWN;
default:
throw new IllegalArgumentException("Unhandled state: " + kernelState);
}
}
/**
* The potential kernel states.
*/
public enum State {
/**
* Modelling mode.
*/
MODELLING,
/**
* Operating.
*/
OPERATING,
/**
* Shutting down.
*/
SHUTDOWN,
/**
* Logged in.
*/
LOGGED_IN,
/**
* Disconnected.
*/
DISCONNECTED;
}
}

View File

@@ -0,0 +1,122 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.operationsdesk.exchange;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import org.opentcs.access.SharedKernelServicePortalProvider;
import org.opentcs.components.Lifecycle;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.guing.base.model.elements.LocationModel;
import org.opentcs.guing.base.model.elements.PathModel;
import org.opentcs.guing.base.model.elements.VehicleModel;
import org.opentcs.guing.common.event.SystemModelTransitionEvent;
import org.opentcs.guing.common.persistence.ModelManager;
import org.opentcs.operationsdesk.exchange.adapter.LocationLockAdapter;
import org.opentcs.operationsdesk.exchange.adapter.PathLockAdapter;
import org.opentcs.operationsdesk.exchange.adapter.VehicleAllowedOrderTypesAdapter;
import org.opentcs.operationsdesk.exchange.adapter.VehicleEnergyLevelThresholdSetAdapter;
import org.opentcs.operationsdesk.exchange.adapter.VehicleEnvelopeKeyAdapter;
import org.opentcs.operationsdesk.exchange.adapter.VehiclePausedAdapter;
import org.opentcs.util.event.EventHandler;
import org.opentcs.util.event.EventSource;
/**
* Handles registering of model attribute adapters that update a model component's attribute with
* the kernel when it changes.
*/
public class AttributeAdapterRegistry
implements
EventHandler,
Lifecycle {
/**
* Provides access to a portal.
*/
private final SharedKernelServicePortalProvider portalProvider;
/**
* The model manager.
*/
private final ModelManager modelManager;
/**
* The event soruce we're registering with.
*/
private final EventSource eventSource;
/**
* Whether this instance is initialized or not.
*/
private boolean initialized;
@Inject
public AttributeAdapterRegistry(
SharedKernelServicePortalProvider portalProvider,
ModelManager modelManager,
@ApplicationEventBus
EventSource eventSource
) {
this.portalProvider = requireNonNull(portalProvider, "portalProvider");
this.modelManager = requireNonNull(modelManager, "modelManager");
this.eventSource = requireNonNull(eventSource, "eventSource");
}
@Override
public void initialize() {
if (isInitialized()) {
return;
}
eventSource.subscribe(this);
initialized = true;
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void terminate() {
if (!isInitialized()) {
return;
}
eventSource.unsubscribe(this);
initialized = false;
}
@Override
public void onEvent(Object event) {
if (event instanceof SystemModelTransitionEvent) {
SystemModelTransitionEvent evt = (SystemModelTransitionEvent) event;
switch (evt.getStage()) {
case LOADED:
registerAdapters();
break;
default:
}
}
}
private void registerAdapters() {
for (VehicleModel model : modelManager.getModel().getVehicleModels()) {
model.addAttributesChangeListener(
new VehicleAllowedOrderTypesAdapter(
portalProvider,
model
)
);
model.addAttributesChangeListener(new VehiclePausedAdapter(portalProvider, model));
model.addAttributesChangeListener(new VehicleEnvelopeKeyAdapter(portalProvider, model));
model.addAttributesChangeListener(
new VehicleEnergyLevelThresholdSetAdapter(portalProvider, model)
);
}
for (PathModel model : modelManager.getModel().getPathModels()) {
model.addAttributesChangeListener(new PathLockAdapter(portalProvider, model));
}
for (LocationModel model : modelManager.getModel().getLocationModels()) {
model.addAttributesChangeListener(new LocationLockAdapter(portalProvider, model));
}
}
}

Some files were not shown because too many files have changed in this diff Show More