mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-12 08:37:25 -05:00
#829 Integrates JMBE Creator with new user preferences editor for auto-downloading and compiling the JMBE library from within sdrtrunk. (#844)
Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
@@ -38,6 +38,8 @@ import io.github.dsheirer.gui.preference.PreferenceEditorType;
|
||||
import io.github.dsheirer.gui.preference.UserPreferencesEditor;
|
||||
import io.github.dsheirer.gui.preference.ViewUserPreferenceEditorRequest;
|
||||
import io.github.dsheirer.icon.IconModel;
|
||||
import io.github.dsheirer.jmbe.JmbeEditor;
|
||||
import io.github.dsheirer.jmbe.JmbeEditorRequest;
|
||||
import io.github.dsheirer.module.log.EventLogManager;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
@@ -68,12 +70,14 @@ public class JavaFxWindowManager extends Application
|
||||
public static final String USER_PREFERENCES_EDITOR = "preferences";
|
||||
public static final String STAGE_MONITOR_KEY_CHANNEL_MAP_EDITOR = "channel.map";
|
||||
public static final String STAGE_MONITOR_KEY_ICON_MANAGER_EDITOR = "icon.manager";
|
||||
public static final String STAGE_MONITOR_KEY_JMBE_EDITOR = "jmbe.editor";
|
||||
public static final String STAGE_MONITOR_KEY_PLAYLIST_EDITOR = "playlist";
|
||||
public static final String STAGE_MONITOR_KEY_USER_PREFERENCES_EDITOR = "user.preferences";
|
||||
|
||||
private JFXPanel mJFXPanel;
|
||||
private ChannelMapEditor mChannelMapEditor;
|
||||
private IconManager mIconManager;
|
||||
private JmbeEditor mJmbeEditor;
|
||||
private PlaylistEditor mPlaylistEditor;
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private UserPreferences mUserPreferences;
|
||||
@@ -81,6 +85,7 @@ public class JavaFxWindowManager extends Application
|
||||
|
||||
private Stage mChannelMapStage;
|
||||
private Stage mIconManagerStage;
|
||||
private Stage mJmbeEditorStage;
|
||||
private Stage mPlaylistStage;
|
||||
private Stage mUserPreferencesStage;
|
||||
|
||||
@@ -205,6 +210,56 @@ public class JavaFxWindowManager extends Application
|
||||
return mIconManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a JMBE s editor request
|
||||
*/
|
||||
@Subscribe
|
||||
public void process(final JmbeEditorRequest request)
|
||||
{
|
||||
if(request.isCloseEditorRequest())
|
||||
{
|
||||
execute(() -> {
|
||||
getJmbeEditorStage().hide();
|
||||
mJmbeEditorStage = null;
|
||||
mJmbeEditor = null;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
execute(() -> {
|
||||
getJmbeEditorStage().show();
|
||||
getJmbeEditorStage().requestFocus();
|
||||
getJmbeEditorStage().toFront();
|
||||
getJmbeEditor().process(request);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public Stage getJmbeEditorStage()
|
||||
{
|
||||
if(mJmbeEditorStage == null)
|
||||
{
|
||||
createJFXPanel();
|
||||
Scene scene = new Scene(getJmbeEditor(), 650, 650);
|
||||
mJmbeEditorStage = new Stage();
|
||||
mJmbeEditorStage.setTitle("sdrtrunk - JMBE Library Updater");
|
||||
mJmbeEditorStage.setScene(scene);
|
||||
mUserPreferences.getJavaFxPreferences().monitor(mJmbeEditorStage, STAGE_MONITOR_KEY_JMBE_EDITOR);
|
||||
}
|
||||
|
||||
return mJmbeEditorStage;
|
||||
}
|
||||
|
||||
public JmbeEditor getJmbeEditor()
|
||||
{
|
||||
if(mJmbeEditor == null)
|
||||
{
|
||||
mJmbeEditor = new JmbeEditor(mUserPreferences);
|
||||
}
|
||||
|
||||
return mJmbeEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy construct and access the playlist editor
|
||||
*/
|
||||
|
||||
@@ -243,7 +243,7 @@ public class PlaylistEditor extends BorderPane
|
||||
{
|
||||
if(mChannelEditor == null)
|
||||
{
|
||||
mChannelEditor = new ChannelEditor(mPlaylistManager);
|
||||
mChannelEditor = new ChannelEditor(mPlaylistManager, mUserPreferences);
|
||||
}
|
||||
|
||||
return mChannelEditor;
|
||||
|
||||
@@ -30,6 +30,7 @@ import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -60,9 +61,9 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
*/
|
||||
public AMConfigurationEditor(PlaylistManager playlistManager)
|
||||
public AMConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getRecordPane());
|
||||
|
||||
@@ -25,13 +25,17 @@ package io.github.dsheirer.gui.playlist.channel;
|
||||
import io.github.dsheirer.alias.AliasModel;
|
||||
import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.controller.channel.ChannelException;
|
||||
import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.gui.control.MaxLengthUnaryOperator;
|
||||
import io.github.dsheirer.gui.playlist.Editor;
|
||||
import io.github.dsheirer.gui.preference.PreferenceEditorType;
|
||||
import io.github.dsheirer.gui.preference.ViewUserPreferenceEditorRequest;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -48,6 +52,7 @@ import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
@@ -78,6 +83,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelConfigurationEditor.class);
|
||||
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private UserPreferences mUserPreferences;
|
||||
protected EditorModificationListener mEditorModificationListener = new EditorModificationListener();
|
||||
private Button mPlayButton;
|
||||
private TextField mSystemField;
|
||||
@@ -97,9 +103,10 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
|
||||
private IconNode mStopGraphicNode;
|
||||
private ChannelProcessingMonitor mChannelProcessingMonitor = new ChannelProcessingMonitor();
|
||||
|
||||
public ChannelConfigurationEditor(PlaylistManager playlistManager)
|
||||
public ChannelConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
mPlaylistManager = playlistManager;
|
||||
mUserPreferences = userPreferences;
|
||||
|
||||
setMaxWidth(Double.MAX_VALUE);
|
||||
|
||||
@@ -317,6 +324,45 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
|
||||
});
|
||||
}
|
||||
|
||||
if(requiresJmbeLibrarySetup() &&
|
||||
mUserPreferences.getJmbeLibraryPreference().getAlertIfMissingLibraryRequired() &&
|
||||
!getItem().processingProperty().get())
|
||||
{
|
||||
String content = "The decoder for this channel configuration requires the (optional) JMBE " +
|
||||
"library to produce audio and the JMBE library is not currently setup. Do you want to " +
|
||||
"setup the JMBE library?";
|
||||
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, content, ButtonType.YES, ButtonType.NO);
|
||||
alert.setTitle("JMBE Library");
|
||||
alert.setHeaderText("Setup JMBE Library?");
|
||||
|
||||
Label label = new Label(content);
|
||||
label.setMaxWidth(Double.MAX_VALUE);
|
||||
label.setMaxHeight(Double.MAX_VALUE);
|
||||
label.getStyleClass().add("content");
|
||||
label.setWrapText(true);
|
||||
|
||||
CheckBox checkBox = new CheckBox("Don't Show This Again");
|
||||
checkBox.setOnAction(event1 -> {
|
||||
boolean dontShowAgain = checkBox.isSelected();
|
||||
mUserPreferences.getJmbeLibraryPreference().setAlertIfMissingLibraryRequired(!dontShowAgain);
|
||||
});
|
||||
|
||||
VBox contentBox = new VBox();
|
||||
contentBox.setPrefWidth(360);
|
||||
contentBox.setSpacing(10);
|
||||
contentBox.getChildren().addAll(label, checkBox);
|
||||
alert.getDialogPane().setContent(contentBox);
|
||||
alert.initOwner(getPlayButton().getScene().getWindow());
|
||||
Optional<ButtonType> optionalButtonType = alert.showAndWait();
|
||||
|
||||
if(optionalButtonType.isPresent() && optionalButtonType.get() == ButtonType.YES)
|
||||
{
|
||||
MyEventBus.getEventBus().post(new ViewUserPreferenceEditorRequest(PreferenceEditorType.JMBE_LIBRARY));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!getItem().processingProperty().get())
|
||||
{
|
||||
ThreadPool.SCHEDULED.execute(() -> {
|
||||
@@ -366,6 +412,17 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
|
||||
return mPlayButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the decoder type for the channel configuration requires the JMBE library and if the
|
||||
* application is not currently setup for the JMBE library.
|
||||
*/
|
||||
private boolean requiresJmbeLibrarySetup()
|
||||
{
|
||||
return getItem() != null &&
|
||||
getItem().getDecodeConfiguration().getDecoderType().providesMBEAudioFrames() &&
|
||||
!mUserPreferences.getJmbeLibraryPreference().hasJmbeLibraryPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the text and graphic of the channel play button to reflect the playing state of the channel
|
||||
*/
|
||||
|
||||
@@ -24,6 +24,7 @@ package io.github.dsheirer.gui.playlist.channel;
|
||||
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -44,26 +45,27 @@ public class ChannelConfigurationEditorFactory
|
||||
* @param playlistManager for the editor
|
||||
* @return constructed editor
|
||||
*/
|
||||
public static ChannelConfigurationEditor getEditor(DecoderType decoderType, PlaylistManager playlistManager)
|
||||
public static ChannelConfigurationEditor getEditor(DecoderType decoderType, PlaylistManager playlistManager,
|
||||
UserPreferences userPreferences)
|
||||
{
|
||||
switch(decoderType)
|
||||
{
|
||||
case AM:
|
||||
return new AMConfigurationEditor(playlistManager);
|
||||
return new AMConfigurationEditor(playlistManager, userPreferences);
|
||||
case NBFM:
|
||||
return new NBFMConfigurationEditor(playlistManager);
|
||||
return new NBFMConfigurationEditor(playlistManager, userPreferences);
|
||||
case LTR_NET:
|
||||
return new LTRNetConfigurationEditor(playlistManager);
|
||||
return new LTRNetConfigurationEditor(playlistManager, userPreferences);
|
||||
case LTR:
|
||||
return new LTRConfigurationEditor(playlistManager);
|
||||
return new LTRConfigurationEditor(playlistManager, userPreferences);
|
||||
case MPT1327:
|
||||
return new MPT1327ConfigurationEditor(playlistManager);
|
||||
return new MPT1327ConfigurationEditor(playlistManager, userPreferences);
|
||||
case PASSPORT:
|
||||
return new PassportConfigurationEditor(playlistManager);
|
||||
return new PassportConfigurationEditor(playlistManager, userPreferences);
|
||||
case P25_PHASE1:
|
||||
return new P25P1ConfigurationEditor(playlistManager);
|
||||
return new P25P1ConfigurationEditor(playlistManager, userPreferences);
|
||||
case P25_PHASE2:
|
||||
return new P25P2ConfigurationEditor(playlistManager);
|
||||
return new P25P2ConfigurationEditor(playlistManager, userPreferences);
|
||||
default:
|
||||
if(decoderType != null && !mLoggedUnrecognizedTypes.contains(decoderType))
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.github.dsheirer.controller.channel.Channel;
|
||||
import io.github.dsheirer.module.decode.DecoderFactory;
|
||||
import io.github.dsheirer.module.decode.DecoderType;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||
import io.github.dsheirer.source.config.SourceConfigTunerMultipleFrequency;
|
||||
import javafx.application.Platform;
|
||||
@@ -79,6 +80,7 @@ public class ChannelEditor extends SplitPane
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(ChannelEditor.class);
|
||||
private PlaylistManager mPlaylistManager;
|
||||
private UserPreferences mUserPreferences;
|
||||
private TableView<Channel> mChannelTableView;
|
||||
private Label mPlaceholderLabel;
|
||||
private MenuButton mNewButton;
|
||||
@@ -101,10 +103,11 @@ public class ChannelEditor extends SplitPane
|
||||
* Constructs an instance
|
||||
* @param playlistManager containing playlists and channel configurations
|
||||
*/
|
||||
public ChannelEditor(PlaylistManager playlistManager)
|
||||
public ChannelEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
mPlaylistManager = playlistManager;
|
||||
mUnknownConfigurationEditor = new UnknownConfigurationEditor(mPlaylistManager);
|
||||
mUserPreferences = userPreferences;
|
||||
mUnknownConfigurationEditor = new UnknownConfigurationEditor(mPlaylistManager, userPreferences);
|
||||
|
||||
HBox channelsBox = new HBox();
|
||||
channelsBox.setSpacing(10.0);
|
||||
@@ -200,7 +203,8 @@ public class ChannelEditor extends SplitPane
|
||||
|
||||
if(editor == null)
|
||||
{
|
||||
editor = ChannelConfigurationEditorFactory.getEditor(channelDecoderType, mPlaylistManager);
|
||||
editor = ChannelConfigurationEditorFactory.getEditor(channelDecoderType, mPlaylistManager,
|
||||
mUserPreferences);
|
||||
|
||||
if(editor != null)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ import io.github.dsheirer.module.decode.ltrstandard.DecodeConfigLTRStandard;
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -74,10 +75,11 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public LTRConfigurationEditor(PlaylistManager playlistManager)
|
||||
public LTRConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
|
||||
|
||||
@@ -35,6 +35,7 @@ import io.github.dsheirer.module.decode.ltrnet.DecodeConfigLTRNet;
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -74,10 +75,11 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public LTRNetConfigurationEditor(PlaylistManager playlistManager)
|
||||
public LTRNetConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
|
||||
|
||||
@@ -36,6 +36,7 @@ import io.github.dsheirer.module.decode.mpt1327.DecodeConfigMPT1327;
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -84,10 +85,11 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public MPT1327ConfigurationEditor(PlaylistManager playlistManager)
|
||||
public MPT1327ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getEventLogPane());
|
||||
|
||||
@@ -33,6 +33,7 @@ import io.github.dsheirer.module.decode.nbfm.DecodeConfigNBFM;
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -73,10 +74,11 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public NBFMConfigurationEditor(PlaylistManager playlistManager)
|
||||
public NBFMConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
|
||||
|
||||
@@ -34,6 +34,7 @@ import io.github.dsheirer.module.decode.p25.phase1.P25P1Decoder;
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -80,10 +81,11 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public P25P1ConfigurationEditor(PlaylistManager playlistManager)
|
||||
public P25P1ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getEventLogPane());
|
||||
|
||||
@@ -35,6 +35,7 @@ import io.github.dsheirer.module.decode.p25.phase2.enumeration.ScrambleParameter
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -70,10 +71,11 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public P25P2ConfigurationEditor(PlaylistManager playlistManager)
|
||||
public P25P2ConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getEventLogPane());
|
||||
|
||||
@@ -34,6 +34,7 @@ import io.github.dsheirer.module.decode.passport.DecodeConfigPassport;
|
||||
import io.github.dsheirer.module.log.EventLogType;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.RecorderType;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
@@ -66,10 +67,11 @@ public class PassportConfigurationEditor extends ChannelConfigurationEditor
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param playlistManager
|
||||
* @param userPreferences
|
||||
*/
|
||||
public PassportConfigurationEditor(PlaylistManager playlistManager)
|
||||
public PassportConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getSourcePane());
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
getTitledPanesBox().getChildren().add(getAuxDecoderPane());
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
|
||||
import io.github.dsheirer.module.decode.config.DecodeConfiguration;
|
||||
import io.github.dsheirer.module.log.config.EventLogConfiguration;
|
||||
import io.github.dsheirer.playlist.PlaylistManager;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.record.config.RecordConfiguration;
|
||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||
import javafx.scene.control.TitledPane;
|
||||
@@ -45,9 +46,9 @@ public class UnknownConfigurationEditor extends ChannelConfigurationEditor
|
||||
* Constructs an instance
|
||||
* @param aliasModel
|
||||
*/
|
||||
public UnknownConfigurationEditor(PlaylistManager playlistManager)
|
||||
public UnknownConfigurationEditor(PlaylistManager playlistManager, UserPreferences userPreferences)
|
||||
{
|
||||
super(playlistManager);
|
||||
super(playlistManager, userPreferences);
|
||||
getTitledPanesBox().getChildren().add(getDecoderPane());
|
||||
}
|
||||
|
||||
|
||||
@@ -22,17 +22,28 @@ package io.github.dsheirer.gui.preference.decoder;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.jmbe.JmbeCreator;
|
||||
import io.github.dsheirer.jmbe.JmbeEditorRequest;
|
||||
import io.github.dsheirer.jmbe.github.GitHub;
|
||||
import io.github.dsheirer.jmbe.github.Release;
|
||||
import io.github.dsheirer.jmbe.github.Version;
|
||||
import io.github.dsheirer.preference.PreferenceType;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import io.github.dsheirer.preference.decoder.JmbeLibraryPreference;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
@@ -45,27 +56,64 @@ import java.nio.file.Path;
|
||||
/**
|
||||
* Preference settings for decoders
|
||||
*/
|
||||
public class JmbeLibraryPreferenceEditor extends HBox
|
||||
public class JmbeLibraryPreferenceEditor extends VBox
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(JmbeLibraryPreferenceEditor.class);
|
||||
|
||||
private static final String PATH_NOT_SET = "(not set)";
|
||||
private JmbeLibraryPreference mJmbeLibraryPreference;
|
||||
private static final String CREATE_LIBRARY = "Create Library";
|
||||
private static final String CHECK_FOR_UPDATE = "Check For Library Update";
|
||||
private static final String LIBRARY_NOT_SETUP = "None. Click Select or Create Library button to setup.";
|
||||
|
||||
private UserPreferences mUserPreferences;
|
||||
private GridPane mEditorPane;
|
||||
private Label mJmbeLibraryLabel;
|
||||
private Button mPathToJmbeLibraryButton;
|
||||
private Button mPathToJmbeLibraryResetButton;
|
||||
private Label mJmbeVersionLabel;
|
||||
private Label mPathToJmbeLibraryLabel;
|
||||
private Button mSelectButton;
|
||||
private Button mResetButton;
|
||||
private Button mCreateButton;
|
||||
private HBox mButtonsBox;
|
||||
private CheckBox mAlertUserWhenMissingCheckBox;
|
||||
|
||||
public JmbeLibraryPreferenceEditor(UserPreferences userPreferences)
|
||||
{
|
||||
mJmbeLibraryPreference = userPreferences.getJmbeLibraryPreference();
|
||||
mUserPreferences = userPreferences;
|
||||
|
||||
//Register to receive directory preference update notifications so we can update the path labels
|
||||
MyEventBus.getEventBus().register(this);
|
||||
|
||||
HBox.setHgrow(getEditorPane(), Priority.ALWAYS);
|
||||
getChildren().add(getEditorPane());
|
||||
setPadding(new Insets(10,10,10,10));
|
||||
setSpacing(10);
|
||||
getChildren().addAll(getEditorPane(), getButtonsBox(), getAlertUserWhenMissingCheckBox());
|
||||
}
|
||||
|
||||
private CheckBox getAlertUserWhenMissingCheckBox()
|
||||
{
|
||||
if(mAlertUserWhenMissingCheckBox == null)
|
||||
{
|
||||
mAlertUserWhenMissingCheckBox = new CheckBox("Alert when decoder requires missing JMBE library");
|
||||
mAlertUserWhenMissingCheckBox.setSelected(mUserPreferences.getJmbeLibraryPreference()
|
||||
.getAlertIfMissingLibraryRequired());
|
||||
mAlertUserWhenMissingCheckBox.setOnAction(event -> {
|
||||
boolean alert = mAlertUserWhenMissingCheckBox.isSelected();
|
||||
mUserPreferences.getJmbeLibraryPreference().setAlertIfMissingLibraryRequired(alert);
|
||||
});
|
||||
}
|
||||
|
||||
return mAlertUserWhenMissingCheckBox;
|
||||
}
|
||||
|
||||
private HBox getButtonsBox()
|
||||
{
|
||||
if(mButtonsBox == null)
|
||||
{
|
||||
mButtonsBox = new HBox();
|
||||
mButtonsBox.setSpacing(10);
|
||||
mButtonsBox.getChildren().addAll(getCreateButton(), getSelectButton(), getResetButton());
|
||||
}
|
||||
|
||||
return mButtonsBox;
|
||||
}
|
||||
|
||||
private GridPane getEditorPane()
|
||||
@@ -73,85 +121,206 @@ public class JmbeLibraryPreferenceEditor extends HBox
|
||||
if(mEditorPane == null)
|
||||
{
|
||||
mEditorPane = new GridPane();
|
||||
mEditorPane.setPadding(new Insets(10, 10, 10, 10));
|
||||
mEditorPane.setVgap(10);
|
||||
mEditorPane.setHgap(10);
|
||||
|
||||
int row = 0;
|
||||
|
||||
GridPane.setMargin(getJmbeLibraryLabel(), new Insets(0, 10, 0, 0));
|
||||
mEditorPane.add(getJmbeLibraryLabel(), 0, row);
|
||||
mEditorPane.add(getJmbeLibraryLabel(), 0, row, 2, 1);
|
||||
|
||||
Label versionLabel = new Label("Current Version:");
|
||||
GridPane.setHalignment(versionLabel, HPos.RIGHT);
|
||||
mEditorPane.add(versionLabel, 0, ++row);
|
||||
|
||||
mEditorPane.add(getJmbeVersionLabel(), 1, row);
|
||||
|
||||
Label fileLabel = new Label("File:");
|
||||
GridPane.setHalignment(fileLabel, HPos.RIGHT);
|
||||
mEditorPane.add(fileLabel, 0, ++row);
|
||||
|
||||
GridPane.setMargin(getPathToJmbeLibraryLabel(), new Insets(0, 10, 0, 0));
|
||||
mEditorPane.add(getPathToJmbeLibraryLabel(), 1, row);
|
||||
|
||||
GridPane.setMargin(getPathToJmbeLibraryButton(), new Insets(2, 10, 2, 0));
|
||||
mEditorPane.add(getPathToJmbeLibraryButton(), 2, row);
|
||||
|
||||
GridPane.setMargin(getPathToJmbeLibraryResetButton(), new Insets(2, 0, 2, 0));
|
||||
mEditorPane.add(getPathToJmbeLibraryResetButton(), 3, row++);
|
||||
}
|
||||
|
||||
return mEditorPane;
|
||||
}
|
||||
|
||||
private Button getCreateButton()
|
||||
{
|
||||
if(mCreateButton == null)
|
||||
{
|
||||
mCreateButton = new Button();
|
||||
mCreateButton.setText(mUserPreferences.getJmbeLibraryPreference()
|
||||
.getPathJmbeLibrary() != null ? CHECK_FOR_UPDATE : CREATE_LIBRARY);
|
||||
mCreateButton.setOnAction(event -> checkForUpdatedLibrary());
|
||||
}
|
||||
|
||||
return mCreateButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for availability of an updated JMBE library
|
||||
*/
|
||||
private void checkForUpdatedLibrary()
|
||||
{
|
||||
ThreadPool.SCHEDULED.execute(() -> {
|
||||
try
|
||||
{
|
||||
Version current = mUserPreferences.getJmbeLibraryPreference().getCurrentVersion();
|
||||
final Release release = GitHub.getLatestRelease(JmbeCreator.GITHUB_JMBE_RELEASES_URL);
|
||||
|
||||
mLog.info("Checking for JMBE Library Updates ...");
|
||||
mLog.info("Current: " + (current != null ? current.toString() : "empty"));
|
||||
|
||||
final boolean canUpdate = (release != null) && ((current == null) ||
|
||||
(release.getVersion().compareTo(current) > 0));
|
||||
|
||||
if(release != null)
|
||||
{
|
||||
mLog.info("Available: " + release.getVersion().toString());
|
||||
}
|
||||
|
||||
if(canUpdate)
|
||||
{
|
||||
mLog.info("JMBE Library update is available");
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.info("No JMBE library update is available at this time");
|
||||
}
|
||||
|
||||
Platform.runLater(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(canUpdate)
|
||||
{
|
||||
String content = "JMBE library version " + release.getVersion().toString() +
|
||||
" is available. Would you like to download the latest source code and " +
|
||||
"create an updated JMBE library?";
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION, content, ButtonType.YES, ButtonType.NO);
|
||||
alert.setResizable(true);
|
||||
|
||||
//Workaroud for dialog sizing issue on Windows
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
|
||||
alert.setTitle("JMBE Library Update Check");
|
||||
alert.setHeaderText("Update is available");
|
||||
alert.initOwner(getCreateButton().getScene().getWindow());
|
||||
alert.showAndWait().ifPresent(buttonType -> {
|
||||
if(buttonType == ButtonType.YES)
|
||||
{
|
||||
mLog.info("Posting JMBE editor request to event bus");
|
||||
MyEventBus.getEventBus().post(new JmbeEditorRequest(release));
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION,
|
||||
"No JMBE library update is available.", ButtonType.OK);
|
||||
alert.setTitle("JMBE Library Update Check");
|
||||
if(release != null)
|
||||
{
|
||||
alert.setHeaderText("No update available");
|
||||
}
|
||||
else
|
||||
{
|
||||
alert.setHeaderText("Unable to determine latest release version. Check network connection");
|
||||
}
|
||||
alert.initOwner(getCreateButton().getScene().getWindow());
|
||||
alert.showAndWait();
|
||||
}
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
mLog.error("Error during JavaFX portion of create library");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
mLog.error("Error during create library", t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Label getJmbeLibraryLabel()
|
||||
{
|
||||
if(mJmbeLibraryLabel == null)
|
||||
{
|
||||
mJmbeLibraryLabel = new Label("JMBE Audio Library:");
|
||||
mJmbeLibraryLabel = new Label("JMBE Audio Library");
|
||||
}
|
||||
|
||||
return mJmbeLibraryLabel;
|
||||
}
|
||||
|
||||
private Button getPathToJmbeLibraryButton()
|
||||
private Label getJmbeVersionLabel()
|
||||
{
|
||||
if(mPathToJmbeLibraryButton == null)
|
||||
if(mJmbeVersionLabel == null)
|
||||
{
|
||||
mPathToJmbeLibraryButton = new Button("Change...");
|
||||
mPathToJmbeLibraryButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
mJmbeVersionLabel = new Label();
|
||||
Version version = mUserPreferences.getJmbeLibraryPreference().getCurrentVersion();
|
||||
|
||||
if(version != null)
|
||||
{
|
||||
mJmbeVersionLabel.setText(version.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
mJmbeVersionLabel.setText(LIBRARY_NOT_SETUP);
|
||||
}
|
||||
}
|
||||
|
||||
return mJmbeVersionLabel;
|
||||
}
|
||||
|
||||
private Button getSelectButton()
|
||||
{
|
||||
if(mSelectButton == null)
|
||||
{
|
||||
mSelectButton = new Button("Select...");
|
||||
mSelectButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Select JMBE Audio Library Location");
|
||||
Stage stage = (Stage)getPathToJmbeLibraryButton().getScene().getWindow();
|
||||
fileChooser.setInitialDirectory(mUserPreferences.getDirectoryPreference().getDefaultJmbeDirectory().toFile());
|
||||
Stage stage = (Stage)getSelectButton().getScene().getWindow();
|
||||
File selected = fileChooser.showOpenDialog(stage);
|
||||
|
||||
if(selected != null)
|
||||
{
|
||||
mJmbeLibraryPreference.setPathJmbeLibrary(selected.toPath());
|
||||
mUserPreferences.getJmbeLibraryPreference().setPathJmbeLibrary(selected.toPath());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mPathToJmbeLibraryButton;
|
||||
return mSelectButton;
|
||||
}
|
||||
|
||||
private Button getPathToJmbeLibraryResetButton()
|
||||
private Button getResetButton()
|
||||
{
|
||||
if(mPathToJmbeLibraryResetButton == null)
|
||||
if(mResetButton == null)
|
||||
{
|
||||
mPathToJmbeLibraryResetButton = new Button("Reset");
|
||||
mPathToJmbeLibraryResetButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
mJmbeLibraryPreference.resetPathJmbeLibrary();
|
||||
}
|
||||
});
|
||||
mResetButton = new Button("Reset");
|
||||
mResetButton.setOnAction(event -> mUserPreferences.getJmbeLibraryPreference().resetPathJmbeLibrary());
|
||||
}
|
||||
|
||||
return mPathToJmbeLibraryResetButton;
|
||||
return mResetButton;
|
||||
}
|
||||
|
||||
private Label getPathToJmbeLibraryLabel()
|
||||
{
|
||||
if(mPathToJmbeLibraryLabel == null)
|
||||
{
|
||||
Path path = mJmbeLibraryPreference.getPathJmbeLibrary();
|
||||
Path path = mUserPreferences.getJmbeLibraryPreference().getPathJmbeLibrary();
|
||||
mPathToJmbeLibraryLabel = new Label(path != null ? path.toString() : PATH_NOT_SET);
|
||||
}
|
||||
|
||||
@@ -163,8 +332,14 @@ public class JmbeLibraryPreferenceEditor extends HBox
|
||||
{
|
||||
if(preferenceType != null && preferenceType == PreferenceType.JMBE_LIBRARY)
|
||||
{
|
||||
Path path = mJmbeLibraryPreference.getPathJmbeLibrary();
|
||||
Path path = mUserPreferences.getJmbeLibraryPreference().getPathJmbeLibrary();
|
||||
getPathToJmbeLibraryLabel().setText(path != null ? path.toString() : PATH_NOT_SET);
|
||||
Version version = mUserPreferences.getJmbeLibraryPreference().getCurrentVersion();
|
||||
getJmbeVersionLabel().setText(version != null ? version.toString() : LIBRARY_NOT_SETUP);
|
||||
getCreateButton().setText(mUserPreferences.getJmbeLibraryPreference()
|
||||
.getPathJmbeLibrary() != null ? CHECK_FOR_UPDATE : CREATE_LIBRARY);
|
||||
getAlertUserWhenMissingCheckBox().setSelected(mUserPreferences.getJmbeLibraryPreference()
|
||||
.getAlertIfMissingLibraryRequired());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,11 @@ public class DirectoryPreferenceEditor extends HBox
|
||||
private Button mResetEventLogsButton;
|
||||
private Label mEventLogsPathLabel;
|
||||
|
||||
private Label mJmbeLabel;
|
||||
private Button mChangeJmbeButton;
|
||||
private Button mResetJmbeButton;
|
||||
private Label mJmbePathLabel;
|
||||
|
||||
private Label mPlaylistLabel;
|
||||
private Button mChangePlaylistButton;
|
||||
private Button mResetPlaylistButton;
|
||||
@@ -157,6 +162,19 @@ public class DirectoryPreferenceEditor extends HBox
|
||||
mEditorPane.add(getResetEventLogsButton(), 3, row++);
|
||||
|
||||
|
||||
GridPane.setMargin(getJmbeLabel(), new Insets(0, 10, 0, 0));
|
||||
mEditorPane.add(getJmbeLabel(), 0, row);
|
||||
|
||||
GridPane.setMargin(getJmbePathLabel(), new Insets(0, 10, 0, 0));
|
||||
mEditorPane.add(getJmbePathLabel(), 1, row);
|
||||
|
||||
GridPane.setMargin(getChangeJmbeButton(), new Insets(2, 10, 2, 0));
|
||||
mEditorPane.add(getChangeJmbeButton(), 2, row);
|
||||
|
||||
GridPane.setMargin(getResetJmbeButton(), new Insets(2, 0, 2, 0));
|
||||
mEditorPane.add(getResetJmbeButton(), 3, row++);
|
||||
|
||||
|
||||
GridPane.setMargin(getPlaylistLabel(), new Insets(0, 10, 0, 0));
|
||||
mEditorPane.add(getPlaylistLabel(), 0, row);
|
||||
|
||||
@@ -407,6 +425,71 @@ public class DirectoryPreferenceEditor extends HBox
|
||||
return mEventLogsPathLabel;
|
||||
}
|
||||
|
||||
private Label getJmbeLabel()
|
||||
{
|
||||
if(mJmbeLabel == null)
|
||||
{
|
||||
mJmbeLabel = new Label("JMBE Libraries");
|
||||
}
|
||||
|
||||
return mJmbeLabel;
|
||||
}
|
||||
|
||||
private Button getChangeJmbeButton()
|
||||
{
|
||||
if(mChangeJmbeButton == null)
|
||||
{
|
||||
mChangeJmbeButton = new Button("Change...");
|
||||
mChangeJmbeButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
DirectoryChooser directoryChooser = new DirectoryChooser();
|
||||
directoryChooser.setTitle("Select JMBE Folder");
|
||||
directoryChooser.setInitialDirectory(mDirectoryPreference.getDirectoryJmbe().toFile());
|
||||
Stage stage = (Stage)getChangeJmbeButton().getScene().getWindow();
|
||||
File selected = directoryChooser.showDialog(stage);
|
||||
|
||||
if(selected != null)
|
||||
{
|
||||
mDirectoryPreference.setDirectoryJmbe(selected.toPath());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mChangeJmbeButton;
|
||||
}
|
||||
|
||||
private Button getResetJmbeButton()
|
||||
{
|
||||
if(mResetJmbeButton == null)
|
||||
{
|
||||
mResetJmbeButton = new Button("Reset");
|
||||
mResetJmbeButton.setOnAction(new EventHandler<ActionEvent>()
|
||||
{
|
||||
@Override
|
||||
public void handle(ActionEvent event)
|
||||
{
|
||||
mDirectoryPreference.resetDirectoryJmbe();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return mResetJmbeButton;
|
||||
}
|
||||
|
||||
private Label getJmbePathLabel()
|
||||
{
|
||||
if(mJmbePathLabel == null)
|
||||
{
|
||||
mJmbePathLabel = new Label(mDirectoryPreference.getDirectoryJmbe().toString());
|
||||
}
|
||||
|
||||
return mJmbePathLabel;
|
||||
}
|
||||
|
||||
private Label getPlaylistLabel()
|
||||
{
|
||||
if(mPlaylistLabel == null)
|
||||
|
||||
323
src/main/java/io/github/dsheirer/jmbe/JmbeCreator.java
Normal file
323
src/main/java/io/github/dsheirer/jmbe/JmbeCreator.java
Normal file
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe;
|
||||
|
||||
import io.github.dsheirer.jmbe.github.Asset;
|
||||
import io.github.dsheirer.jmbe.github.GitHub;
|
||||
import io.github.dsheirer.jmbe.github.Release;
|
||||
import io.github.dsheirer.util.FileUtil;
|
||||
import io.github.dsheirer.util.OSType;
|
||||
import io.github.dsheirer.util.ThreadPool;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.rauschig.jarchivelib.ArchiveFormat;
|
||||
import org.rauschig.jarchivelib.Archiver;
|
||||
import org.rauschig.jarchivelib.ArchiverFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* Creates the JMBE library by downloading the JMBE Creator CLI application from GitHub and executing it.
|
||||
*/
|
||||
public class JmbeCreator
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(JmbeCreator.class);
|
||||
public static final String GITHUB_JMBE_RELEASES_URL = "https://api.github.com/repos/dsheirer/jmbe/releases";
|
||||
public static final String CREATOR_SCRIPT_LINUX = "creator";
|
||||
public static final String CREATOR_SCRIPT_WINDOWS = "creator.bat";
|
||||
|
||||
private StringProperty mConsoleOutput = new SimpleStringProperty();
|
||||
private BooleanProperty mCompleteProperty = new SimpleBooleanProperty();
|
||||
private boolean mHasErrors = false;
|
||||
private Release mRelease;
|
||||
private Path mLibraryPath;
|
||||
private StringBuilder mConsoleStringBuilder = new StringBuilder();
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
* @param release for the version to create
|
||||
* @param library path where the library should be created
|
||||
*/
|
||||
public JmbeCreator(Release release, Path library)
|
||||
{
|
||||
mRelease = release;
|
||||
mLibraryPath = library;
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to where the library should be created
|
||||
*/
|
||||
public Path getLibraryPath()
|
||||
{
|
||||
return mLibraryPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property that indicates if the creation process has finished.
|
||||
*/
|
||||
public BooleanProperty completeProperty()
|
||||
{
|
||||
return mCompleteProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Console output from the build process.
|
||||
*/
|
||||
public StringProperty consoleOutputProperty()
|
||||
{
|
||||
return mConsoleOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints (adds) the message text to the console property
|
||||
* @param message to add
|
||||
*/
|
||||
private void printToConsole(String message)
|
||||
{
|
||||
mConsoleStringBuilder.append(message).append("\n");
|
||||
final String console = mConsoleStringBuilder.toString();
|
||||
Platform.runLater(() -> consoleOutputProperty().setValue(console));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the build process completed successfully (false) or there were errors (true).
|
||||
*/
|
||||
public boolean hasErrors()
|
||||
{
|
||||
return mHasErrors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the build process that downloads the JMBE creator utility, unzips it, and commands the utility
|
||||
* to create the library at the specified library path.
|
||||
*/
|
||||
public void execute()
|
||||
{
|
||||
final Asset asset = getJMBECreatorAsset(mRelease);
|
||||
|
||||
if(asset != null)
|
||||
{
|
||||
ThreadPool.SCHEDULED.execute(() -> {
|
||||
Path tempDirectory = null;
|
||||
try
|
||||
{
|
||||
tempDirectory = Files.createTempDirectory("sdrtrunk-jmbe-creator");
|
||||
printToConsole("Created: Temp Directory [" + tempDirectory.toString() + "]");
|
||||
printToConsole("Downloading: JMBE Creator [" + asset.toString() + "]");
|
||||
printToConsole("Please wait ...");
|
||||
Path creator = GitHub.downloadArtifact(asset.getDownloadUrl(), tempDirectory);
|
||||
|
||||
if(creator != null)
|
||||
{
|
||||
printToConsole("Downloaded: JMBE Creator [" + creator.toString() + "]");
|
||||
Path unzipped = creator.getParent();
|
||||
Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.ZIP);
|
||||
archiver.extract(creator.toFile(), unzipped.toFile());
|
||||
printToConsole("Unzipped: [" + unzipped.toString() + "]");
|
||||
|
||||
Path script = null;
|
||||
|
||||
OSType osType = OSType.getCurrentOSType();
|
||||
|
||||
if(osType.isLinux())
|
||||
{
|
||||
script = FileUtil.findFile(unzipped, CREATOR_SCRIPT_LINUX);
|
||||
}
|
||||
else if(osType.isWindows())
|
||||
{
|
||||
script = FileUtil.findFile(unzipped, CREATOR_SCRIPT_WINDOWS);
|
||||
}
|
||||
|
||||
if(script != null)
|
||||
{
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
processBuilder.command(script.toString(), mLibraryPath.toString());
|
||||
|
||||
try
|
||||
{
|
||||
Process process = processBuilder.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
while((line = reader.readLine()) != null)
|
||||
{
|
||||
printToConsole(line);
|
||||
}
|
||||
|
||||
int exitCode = process.waitFor();
|
||||
|
||||
if(exitCode == 0)
|
||||
{
|
||||
printToConsole("Library Created Successfully!");
|
||||
Platform.runLater(() -> completeProperty().set(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateWithErrors("Failed: Exit Code [" + exitCode + "]");
|
||||
mLog.error("Script failed with exit code: " + exitCode);
|
||||
}
|
||||
}
|
||||
catch(InterruptedException ie)
|
||||
{
|
||||
terminateWithErrors("Failed: Script Process was interrupted");
|
||||
mLog.error("Interrupted", ie);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateWithErrors("Failed: Unable to find JMBE creator launch script for this OS");
|
||||
mLog.error("Script was null. Unable to find JMBE creator launch script");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
terminateWithErrors("Failed: Unknown Error - " + t.getLocalizedMessage());
|
||||
mLog.error("Failed to create the JMBE library", t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(tempDirectory != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtils.deleteDirectory(tempDirectory.toFile());
|
||||
printToConsole("Deleted: Temporary Directory [" + tempDirectory.toString() + "]");
|
||||
}
|
||||
catch(IOException ioe)
|
||||
{
|
||||
printToConsole("Failed: Deleting Temporary Directory [" + tempDirectory.toString() + "]");
|
||||
mLog.error("Error deleting temporary directory [" + tempDirectory.toString() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
terminateWithErrors("Failed: Unable to identify correct JMBE creator utility from GitHub " +
|
||||
"repository for this computer's operating system and architecture");
|
||||
mLog.error("Unable to create JMBE library. Can't find JMBE Creator for this OS and architecture");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Terminates the execution and updates flags to indicate error state
|
||||
* @param message to display as console output
|
||||
*/
|
||||
private void terminateWithErrors(String message)
|
||||
{
|
||||
printToConsole(message);
|
||||
printToConsole("Please follow the instructions for manually creating and installing the JMBE library");
|
||||
Platform.runLater(() -> {
|
||||
mHasErrors = true;
|
||||
mCompleteProperty.set(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the correct JMBE creator for this operating system and architecture for the specified release
|
||||
* @param release to find
|
||||
* @return JMBE creator asset or null.
|
||||
*/
|
||||
public static Asset getJMBECreatorAsset(Release release)
|
||||
{
|
||||
OSType osType = OSType.getCurrentOSType();
|
||||
|
||||
if(release != null)
|
||||
{
|
||||
for(Asset asset: release.getAssets())
|
||||
{
|
||||
if(isCorrectAsset(asset, osType))
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the asset is correct for the host operating system and architecture
|
||||
* @param asset to check
|
||||
* @param osType for the current host (OS & architecture)
|
||||
* @return true if the asset is correct for this host.
|
||||
*/
|
||||
public static boolean isCorrectAsset(Asset asset, OSType osType)
|
||||
{
|
||||
if(isJMBECreator(asset))
|
||||
{
|
||||
String name = asset.getName();
|
||||
|
||||
switch(osType)
|
||||
{
|
||||
case LINUX_32:
|
||||
return name.contains("linux") && name.contains("_32");
|
||||
case LINUX_64:
|
||||
return name.contains("linux") && name.contains("_64");
|
||||
case OSX_64:
|
||||
return name.contains("osx") && name.contains("_64");
|
||||
case WINDOWS_32:
|
||||
return name.contains("windows") && name.contains("_32");
|
||||
case WINDOWS_64:
|
||||
return name.contains("windows") && name.contains("_64");
|
||||
case UNKNOWN:
|
||||
case OSX_32:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the GitHub asset has a non-null asset name and is a JMBE Creator asset
|
||||
*/
|
||||
private static boolean isJMBECreator(Asset asset)
|
||||
{
|
||||
return asset.getName() != null && asset.getName().startsWith("jmbe-creator");
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Release release = GitHub.getLatestRelease(GITHUB_JMBE_RELEASES_URL);
|
||||
Path library = Paths.get("/home/denny/temp/jmbe.jar");
|
||||
JmbeCreator jmbeCreator = new JmbeCreator(release, library);
|
||||
|
||||
jmbeCreator.execute();
|
||||
|
||||
while(true);
|
||||
}
|
||||
}
|
||||
327
src/main/java/io/github/dsheirer/jmbe/JmbeEditor.java
Normal file
327
src/main/java/io/github/dsheirer/jmbe/JmbeEditor.java
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe;
|
||||
|
||||
import io.github.dsheirer.eventbus.MyEventBus;
|
||||
import io.github.dsheirer.jmbe.github.Release;
|
||||
import io.github.dsheirer.jmbe.github.Version;
|
||||
import io.github.dsheirer.preference.UserPreferences;
|
||||
import javafx.geometry.HPos;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Separator;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.DirectoryChooser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Editor pane for JMBE Library creator
|
||||
*/
|
||||
public class JmbeEditor extends VBox
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(JmbeEditor.class);
|
||||
private UserPreferences mUserPreferences;
|
||||
private Release mCurrentRelease;
|
||||
private Label mCurrentVersionLabel;
|
||||
private Label mUpdatedVersionLabel;
|
||||
private Label mLibraryPathLabel;
|
||||
private Button mChangeDirectoryButton;
|
||||
private GridPane mLabelGridPane;
|
||||
private Path mLibraryDirectoryPath;
|
||||
private Button mCreateButton;
|
||||
private TextArea mConsoleTextArea;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param userPreferences
|
||||
*/
|
||||
public JmbeEditor(UserPreferences userPreferences)
|
||||
{
|
||||
mUserPreferences = userPreferences;
|
||||
setPadding(new Insets(10,10,10,10));
|
||||
setSpacing(10);
|
||||
Separator separator = new Separator();
|
||||
separator.setMaxWidth(Double.MAX_VALUE);
|
||||
VBox.setVgrow(getConsoleTextArea(), Priority.ALWAYS);
|
||||
getChildren().addAll(getLabelGridPane(), separator, getCreateButton(), getConsoleTextArea());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a request to configure the editor to build the release version specified in the request.
|
||||
* @param request to build a specific release version
|
||||
*/
|
||||
public void process(JmbeEditorRequest request)
|
||||
{
|
||||
if(request != null)
|
||||
{
|
||||
setCurrentRelease(request.getCurrentRelease());
|
||||
}
|
||||
}
|
||||
|
||||
private TextArea getConsoleTextArea()
|
||||
{
|
||||
if(mConsoleTextArea == null)
|
||||
{
|
||||
mConsoleTextArea = new TextArea();
|
||||
mConsoleTextArea.setMaxHeight(Double.MAX_VALUE);
|
||||
mConsoleTextArea.setMaxWidth(Double.MAX_VALUE);
|
||||
}
|
||||
|
||||
return mConsoleTextArea;
|
||||
}
|
||||
|
||||
private Button getCreateButton()
|
||||
{
|
||||
if(mCreateButton == null)
|
||||
{
|
||||
mCreateButton = new Button("Create Library");
|
||||
mCreateButton.setOnAction(event -> {
|
||||
String noticeText = "The JMBE library is available as source code for educational purposes " +
|
||||
"only. It is a written description of how certain voice encoding/decoding algorithms " +
|
||||
"could be implemented. Executable objects compiled or derived from this package may " +
|
||||
"be covered by one or more patents. Users are strongly advised to check for any " +
|
||||
"patent restrictions or licensing requirements before compiling or using this " +
|
||||
"source code.\n\nClicking the YES button indicates that you are requesting to download " +
|
||||
"the JMBE source code and compile the JMBE library.";
|
||||
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING, noticeText, ButtonType.YES, ButtonType.NO);
|
||||
alert.setResizable(true);
|
||||
|
||||
//Workaroud for dialog sizing issue on Windows
|
||||
alert.getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
|
||||
|
||||
alert.setTitle("Download and Compile JMBE Library?");
|
||||
alert.setHeaderText("Do you want to continue?");
|
||||
alert.initOwner(getCreateButton().getScene().getWindow());
|
||||
alert.showAndWait().ifPresent(buttonType -> {
|
||||
if(buttonType == ButtonType.YES)
|
||||
{
|
||||
Path library = getLibraryDirectoryPath().resolve(getJarName(mCurrentRelease.getVersion()));
|
||||
getCreateButton().setDisable(true);
|
||||
createJmbeLibrary(library);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return mCreateButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the JMBE creator and creates the library using the specified path argument.
|
||||
* @param library path
|
||||
*/
|
||||
private void createJmbeLibrary(Path library)
|
||||
{
|
||||
JmbeCreator jmbeCreator = new JmbeCreator(mCurrentRelease, library);
|
||||
getConsoleTextArea().textProperty().bind(jmbeCreator.consoleOutputProperty());
|
||||
jmbeCreator.completeProperty().addListener((observable, oldValue, newValue) -> {
|
||||
getCreateButton().setDisable(false);
|
||||
boolean failed = jmbeCreator.hasErrors();
|
||||
String content = null;
|
||||
if(failed)
|
||||
{
|
||||
content = "JMBE library creation attempt failed. Please update the library manually by " +
|
||||
"downloading the JMBE creator application.";
|
||||
}
|
||||
else
|
||||
{
|
||||
content = "JMBE library successfully created/updated";
|
||||
mUserPreferences.getJmbeLibraryPreference().setPathJmbeLibrary(jmbeCreator.getLibraryPath());
|
||||
getCurrentVersionLabel().setText(mCurrentRelease.getVersion().toString());
|
||||
}
|
||||
Alert alert = new Alert(Alert.AlertType.INFORMATION, content, ButtonType.OK);
|
||||
alert.setTitle("JMBE Library Creator");
|
||||
alert.setHeaderText((failed ? "Attempt failed." : "Success!") + " Please click OK to close this window");
|
||||
alert.initOwner(getCreateButton().getScene().getWindow());
|
||||
alert.showAndWait().ifPresent(buttonType -> {
|
||||
jmbeCreator.completeProperty().unbind();
|
||||
MyEventBus.getEventBus().post(new JmbeEditorRequest(true));
|
||||
});
|
||||
});
|
||||
jmbeCreator.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a jar name for the specified release version
|
||||
* @param version of the GitHub JMBE release
|
||||
* @return JMBE library jar name
|
||||
*/
|
||||
public static String getJarName(Version version)
|
||||
{
|
||||
String name = version.toString();
|
||||
name = name.replace("v", "");
|
||||
return "jmbe-" + name + ".jar";
|
||||
}
|
||||
|
||||
private GridPane getLabelGridPane()
|
||||
{
|
||||
if(mLabelGridPane == null)
|
||||
{
|
||||
mLabelGridPane = new GridPane();
|
||||
mLabelGridPane.setHgap(10);
|
||||
mLabelGridPane.setVgap(10);
|
||||
|
||||
int row = 0;
|
||||
|
||||
Label topLabel = new Label("Create or Update JMBE Library");
|
||||
mLabelGridPane.add(topLabel, 0, row, 2, 1);
|
||||
|
||||
Label currentLabel = new Label("Current Version:");
|
||||
GridPane.setHalignment(currentLabel, HPos.RIGHT);
|
||||
mLabelGridPane.add(currentLabel, 0, ++row);
|
||||
mLabelGridPane.add(getCurrentVersionLabel(), 1, row);
|
||||
|
||||
Label updateLabel = new Label("Updating To Version:");
|
||||
GridPane.setHalignment(updateLabel, HPos.RIGHT);
|
||||
mLabelGridPane.add(updateLabel, 0, ++row);
|
||||
mLabelGridPane.add(getUpdatedVersionLabel(), 1, row);
|
||||
|
||||
Label pathLabel = new Label("Store Library At:");
|
||||
GridPane.setHalignment(pathLabel, HPos.RIGHT);
|
||||
mLabelGridPane.add(pathLabel, 0, ++row);
|
||||
mLabelGridPane.add(getLibraryPathLabel(), 1, row);
|
||||
|
||||
mLabelGridPane.add(getChangeDirectoryButton(), 1, ++row);
|
||||
}
|
||||
|
||||
return mLabelGridPane;
|
||||
}
|
||||
|
||||
private Path getLibraryDirectoryPath()
|
||||
{
|
||||
if(mLibraryDirectoryPath == null)
|
||||
{
|
||||
mLibraryDirectoryPath = mUserPreferences.getDirectoryPreference().getDefaultJmbeDirectory();
|
||||
}
|
||||
|
||||
return mLibraryDirectoryPath;
|
||||
}
|
||||
|
||||
private Button getChangeDirectoryButton()
|
||||
{
|
||||
if(mChangeDirectoryButton == null)
|
||||
{
|
||||
mChangeDirectoryButton = new Button("Change Directory ...");
|
||||
mChangeDirectoryButton.setOnAction(event -> {
|
||||
DirectoryChooser chooser = new DirectoryChooser();
|
||||
chooser.setInitialDirectory(getLibraryDirectoryPath().toFile());
|
||||
chooser.setTitle("JMBE Library Directory");
|
||||
File newDirectory = chooser.showDialog(getChangeDirectoryButton().getScene().getWindow());
|
||||
setLibraryDirectoryPath(newDirectory.toPath());
|
||||
});
|
||||
}
|
||||
|
||||
return mChangeDirectoryButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the library path and updates the display label
|
||||
*/
|
||||
private void setLibraryDirectoryPath(Path path)
|
||||
{
|
||||
if(path != null)
|
||||
{
|
||||
mLibraryDirectoryPath = path;
|
||||
getLibraryPathLabel().setText(mLibraryDirectoryPath.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private Label getLibraryPathLabel()
|
||||
{
|
||||
if(mLibraryPathLabel == null)
|
||||
{
|
||||
mLibraryPathLabel = new Label();
|
||||
|
||||
if(getLibraryDirectoryPath() != null)
|
||||
{
|
||||
mLibraryPathLabel.setText(getLibraryDirectoryPath().toString());
|
||||
}
|
||||
}
|
||||
|
||||
return mLibraryPathLabel;
|
||||
}
|
||||
|
||||
private Label getCurrentVersionLabel()
|
||||
{
|
||||
if(mCurrentVersionLabel == null)
|
||||
{
|
||||
mCurrentVersionLabel = new Label("(empty)");
|
||||
|
||||
Version currentVersion = mUserPreferences.getJmbeLibraryPreference().getCurrentVersion();
|
||||
|
||||
if(currentVersion != null)
|
||||
{
|
||||
mCurrentVersionLabel.setText(currentVersion.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return mCurrentVersionLabel;
|
||||
}
|
||||
|
||||
private Label getUpdatedVersionLabel()
|
||||
{
|
||||
if(mUpdatedVersionLabel == null)
|
||||
{
|
||||
mUpdatedVersionLabel = new Label("(empty)");
|
||||
}
|
||||
|
||||
return mUpdatedVersionLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current release version available from GitHub.
|
||||
* @return current release or null if the release hasn't been set.
|
||||
*/
|
||||
private Release getCurrentRelease()
|
||||
{
|
||||
return mCurrentRelease;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current release version available from GitHub.
|
||||
* @param release version
|
||||
*/
|
||||
public void setCurrentRelease(Release release)
|
||||
{
|
||||
mCurrentRelease = release;
|
||||
|
||||
if(release != null)
|
||||
{
|
||||
Version updateVersion = release.getVersion();
|
||||
|
||||
if(updateVersion != null)
|
||||
{
|
||||
getUpdatedVersionLabel().setText(updateVersion.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/main/java/io/github/dsheirer/jmbe/JmbeEditorRequest.java
Normal file
65
src/main/java/io/github/dsheirer/jmbe/JmbeEditorRequest.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe;
|
||||
|
||||
import io.github.dsheirer.jmbe.github.Release;
|
||||
|
||||
/**
|
||||
* Request to create a JMBE library from the specified GitHub release version
|
||||
*/
|
||||
public class JmbeEditorRequest
|
||||
{
|
||||
private Release mCurrentRelease;
|
||||
private boolean mCloseEditor = false;
|
||||
|
||||
/**
|
||||
* Constructs an instance to request an edit of the specified release
|
||||
* @param release available on GitHub
|
||||
*/
|
||||
public JmbeEditorRequest(Release release)
|
||||
{
|
||||
mCurrentRelease = release;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a request to close and dispose of the editor
|
||||
* @param close
|
||||
*/
|
||||
public JmbeEditorRequest(boolean close)
|
||||
{
|
||||
mCloseEditor = close;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this is a close (and dispose) editor request
|
||||
*/
|
||||
public boolean isCloseEditorRequest()
|
||||
{
|
||||
return mCloseEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release version requested
|
||||
*/
|
||||
public Release getCurrentRelease()
|
||||
{
|
||||
return mCurrentRelease;
|
||||
}
|
||||
}
|
||||
75
src/main/java/io/github/dsheirer/jmbe/github/Asset.java
Normal file
75
src/main/java/io/github/dsheirer/jmbe/github/Asset.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe.github;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* GitHub Asset
|
||||
*/
|
||||
public class Asset
|
||||
{
|
||||
private JsonObject mJsonObject;
|
||||
|
||||
public Asset(JsonObject jsonObject)
|
||||
{
|
||||
mJsonObject = jsonObject;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return getTag("name");
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to download this asset
|
||||
*/
|
||||
public String getDownloadUrl()
|
||||
{
|
||||
return getTag("browser_download_url");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the string contents of a json tag
|
||||
* @param tagName to access
|
||||
* @return string value or null
|
||||
*/
|
||||
private String getTag(String tagName)
|
||||
{
|
||||
if(mJsonObject != null)
|
||||
{
|
||||
JsonElement element = mJsonObject.get(tagName);
|
||||
|
||||
if(!element.isJsonNull())
|
||||
{
|
||||
return element.toString().replace("\"", "");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
175
src/main/java/io/github/dsheirer/jmbe/github/GitHub.java
Normal file
175
src/main/java/io/github/dsheirer/jmbe/github/GitHub.java
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* ******************************************************************************
|
||||
* Copyright (C) 2015-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* *****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe.github;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
/**
|
||||
* Utilities for accessing GitHub repositories and releases
|
||||
*/
|
||||
public class GitHub
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(GitHub.class);
|
||||
|
||||
private GitHub()
|
||||
{
|
||||
//There's nothing to construct in this class
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an artifact to the specified directory
|
||||
* @param url of the artifact to download
|
||||
* @param directory to store the downloaded file
|
||||
* @return path to the downloaded artifact or null
|
||||
*/
|
||||
public static Path downloadArtifact(String url, Path directory)
|
||||
{
|
||||
HttpClient client = HttpClient.newBuilder()
|
||||
.followRedirects(HttpClient.Redirect.ALWAYS)
|
||||
.build();
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url)).build();
|
||||
|
||||
try
|
||||
{
|
||||
HttpResponse<Path> response = client.send(request, HttpResponse.BodyHandlers.ofFileDownload(directory,
|
||||
StandardOpenOption.CREATE, StandardOpenOption.WRITE));
|
||||
|
||||
if(response.statusCode() != 200)
|
||||
{
|
||||
mLog.error("HTTP Download Status Code: " + response.statusCode());
|
||||
}
|
||||
|
||||
return response.body();
|
||||
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
mLog.error("Error downloading source code from GitHub", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the latest release object from the repository.
|
||||
* @param repositoryURL for the GitHub api
|
||||
* @return the latest release or null
|
||||
*/
|
||||
public static Release getLatestRelease(String repositoryURL)
|
||||
{
|
||||
HttpClient httpClient = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(repositoryURL)).build();
|
||||
|
||||
try
|
||||
{
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if(response.statusCode() == 200)
|
||||
{
|
||||
return parseResponse(response.body());
|
||||
}
|
||||
else
|
||||
{
|
||||
mLog.error("Error while fetching latest releases - HTTP:" + response.statusCode());
|
||||
}
|
||||
}
|
||||
catch(IOException | InterruptedException e)
|
||||
{
|
||||
mLog.error("Error while detecting the current release version of JMBE library", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a json string containing an array or GitHub release objects and returns the latest release.
|
||||
* @param json string returned from URL call
|
||||
* @return latest release version
|
||||
*/
|
||||
private static Release parseResponse(String json)
|
||||
{
|
||||
Release release = null;
|
||||
|
||||
if(json != null)
|
||||
{
|
||||
JsonElement element = JsonParser.parseString(json);
|
||||
|
||||
if(element.isJsonArray())
|
||||
{
|
||||
JsonArray array = element.getAsJsonArray();
|
||||
|
||||
for(JsonElement child: array)
|
||||
{
|
||||
if(child.isJsonObject())
|
||||
{
|
||||
JsonObject releaseObject = child.getAsJsonObject();
|
||||
Version version = getVersion(releaseObject);
|
||||
|
||||
if(version != null)
|
||||
{
|
||||
if(release == null || release.getVersion().compareTo(version) < 0)
|
||||
{
|
||||
release = new Release(version, releaseObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return release;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a version object from the tag_name.
|
||||
* @param jsonObject containing a tag_name formatted as: vAAAAA.BBBBB.CCCCx where:
|
||||
* A = major, 0-99999
|
||||
* B = minor, 0-99999
|
||||
* C = release, 0-99999
|
||||
* x = (optional)patch, a-z
|
||||
*
|
||||
* @return version instance or null
|
||||
*/
|
||||
private static Version getVersion(JsonObject jsonObject)
|
||||
{
|
||||
JsonElement tagName = jsonObject.get("tag_name");
|
||||
|
||||
if(tagName != null)
|
||||
{
|
||||
return Version.fromString(tagName.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
159
src/main/java/io/github/dsheirer/jmbe/github/Release.java
Normal file
159
src/main/java/io/github/dsheirer/jmbe/github/Release.java
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe.github;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GitHub release
|
||||
*/
|
||||
public class Release
|
||||
{
|
||||
private final static Logger mLog = LoggerFactory.getLogger(Release.class);
|
||||
|
||||
private Version mVersion;
|
||||
private JsonObject mJsonObject;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param version of the release
|
||||
* @param jsonObject that represents the release
|
||||
*/
|
||||
public Release(Version version, JsonObject jsonObject)
|
||||
{
|
||||
mVersion = version;
|
||||
mJsonObject = jsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Version stamp for the release
|
||||
*/
|
||||
public Version getVersion()
|
||||
{
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* JsonObject for the release
|
||||
*/
|
||||
public JsonObject getJsonObject()
|
||||
{
|
||||
return mJsonObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the release
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return getTag("name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assets URL
|
||||
*/
|
||||
public String getAssetsUrl()
|
||||
{
|
||||
return getTag("assets_url");
|
||||
}
|
||||
|
||||
public List<Asset> getAssets()
|
||||
{
|
||||
List<Asset> assets = new ArrayList<>();
|
||||
JsonArray array = mJsonObject.getAsJsonArray("assets");
|
||||
|
||||
if(!array.isJsonNull())
|
||||
{
|
||||
for(JsonElement element: array)
|
||||
{
|
||||
assets.add(new Asset(element.getAsJsonObject()));
|
||||
}
|
||||
}
|
||||
|
||||
return assets;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML URL
|
||||
*/
|
||||
public String getHtmlUrl()
|
||||
{
|
||||
return getTag("html_url");
|
||||
}
|
||||
|
||||
/**
|
||||
* Zip File Download URL
|
||||
*/
|
||||
public String getDownloadUrl()
|
||||
{
|
||||
return getTag("zipball_url");
|
||||
}
|
||||
|
||||
/**
|
||||
* Access the string contents of a json tag
|
||||
* @param tagName to access
|
||||
* @return string value or null
|
||||
*/
|
||||
private String getTag(String tagName)
|
||||
{
|
||||
if(mJsonObject != null)
|
||||
{
|
||||
JsonElement element = mJsonObject.get(tagName);
|
||||
|
||||
if(!element.isJsonNull())
|
||||
{
|
||||
return element.toString().replace("\"", "");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Indicates if the release has a download URL
|
||||
*/
|
||||
public boolean hasDownloadUrl()
|
||||
{
|
||||
return getDownloadUrl() != null;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\nName:").append(getName());
|
||||
sb.append("\nVersion: ").append(getVersion().toString());
|
||||
sb.append("\nHTML URL:").append(getHtmlUrl());
|
||||
sb.append("\nDownload URL:").append(getDownloadUrl());
|
||||
|
||||
for(Asset asset: getAssets())
|
||||
{
|
||||
sb.append("\nAsset: " + asset.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
226
src/main/java/io/github/dsheirer/jmbe/github/Version.java
Normal file
226
src/main/java/io/github/dsheirer/jmbe/github/Version.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.jmbe.github;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Version representation and parsing class
|
||||
*/
|
||||
public class Version implements Comparable<Version>
|
||||
{
|
||||
public final static Pattern VERSION_PATTERN = Pattern.compile("v?(\\d{1,5}).(\\d{1,5}).(\\d{1,5})(\\w*)");
|
||||
|
||||
private Integer mMajor;
|
||||
private Integer mMinor;
|
||||
private Integer mRelease;
|
||||
private Character mPatch;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param major version
|
||||
* @param minor version
|
||||
* @param release version
|
||||
* @param patch version (optional)
|
||||
*/
|
||||
public Version(int major, int minor, int release, Character patch)
|
||||
{
|
||||
mMajor = major;
|
||||
mMinor = minor;
|
||||
mRelease = release;
|
||||
mPatch = patch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the argument into a version instance.
|
||||
* @param version string (e.g. v1.0.6a)
|
||||
* @return
|
||||
*/
|
||||
public static Version fromString(String version)
|
||||
{
|
||||
if(version != null)
|
||||
{
|
||||
Matcher m = VERSION_PATTERN.matcher(version.replace("\"", ""));
|
||||
|
||||
if(m.matches())
|
||||
{
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
int release = 0;
|
||||
Character patch = null;
|
||||
|
||||
try
|
||||
{
|
||||
major = Integer.parseInt(m.group(1));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Do nothing, we couldn't parse the value
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
minor = Integer.parseInt(m.group(2));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Do nothing, we couldn't parse the value
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
release = Integer.parseInt(m.group(3));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
//Do nothing, we couldn't parse the value
|
||||
}
|
||||
|
||||
String rawPatch = m.group(4);
|
||||
|
||||
if(rawPatch != null && rawPatch.length() >= 1)
|
||||
{
|
||||
patch = rawPatch.charAt(0);
|
||||
}
|
||||
|
||||
return new Version(major, minor, release, patch);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Integer getMajor()
|
||||
{
|
||||
return mMajor;
|
||||
}
|
||||
|
||||
public boolean hasMajor()
|
||||
{
|
||||
return mMajor != null;
|
||||
}
|
||||
|
||||
public Integer getMinor()
|
||||
{
|
||||
return mMinor;
|
||||
}
|
||||
|
||||
public boolean hasMinor()
|
||||
{
|
||||
return mMinor != null;
|
||||
}
|
||||
|
||||
public Integer getRelease()
|
||||
{
|
||||
return mRelease;
|
||||
}
|
||||
|
||||
public boolean hasRelease()
|
||||
{
|
||||
return mRelease != null;
|
||||
}
|
||||
|
||||
public char getPatch()
|
||||
{
|
||||
return mPatch;
|
||||
}
|
||||
|
||||
public boolean hasPatch()
|
||||
{
|
||||
return mPatch != null;
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(hasMajor() ? getMajor() : "x");
|
||||
sb.append(".").append(hasMinor() ? getMinor() : "x");
|
||||
sb.append(".").append(hasRelease() ? getRelease() : "x");
|
||||
if(hasPatch())
|
||||
{
|
||||
sb.append(mPatch);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Version other)
|
||||
{
|
||||
if(hasMajor() && other.hasMajor())
|
||||
{
|
||||
if(getMajor() != other.getMajor())
|
||||
{
|
||||
return Integer.compare(getMajor(), other.getMajor());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(hasMinor() && other.hasMinor())
|
||||
{
|
||||
if(getMinor() != other.getMinor())
|
||||
{
|
||||
return Integer.compare(getMinor(), other.getMinor());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(hasRelease() && other.hasRelease())
|
||||
{
|
||||
if(getRelease() != other.getRelease())
|
||||
{
|
||||
return Integer.compare(getRelease(), other.getRelease());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(hasPatch() && other.hasPatch())
|
||||
{
|
||||
if(getPatch() != other.getPatch())
|
||||
{
|
||||
return Character.compare(getPatch(), other.getPatch());
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return hasPatch() ? 1 : -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return hasRelease() ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return hasMinor() ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return hasMajor() ? -1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
package io.github.dsheirer.preference.decoder;
|
||||
|
||||
import io.github.dsheirer.jmbe.github.Version;
|
||||
import io.github.dsheirer.preference.Preference;
|
||||
import io.github.dsheirer.preference.PreferenceType;
|
||||
import io.github.dsheirer.sample.Listener;
|
||||
@@ -32,6 +33,8 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.prefs.Preferences;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Decoder preferences
|
||||
@@ -42,7 +45,10 @@ public class JmbeLibraryPreference extends Preference
|
||||
private Preferences mPreferences = Preferences.userNodeForPackage(JmbeLibraryPreference.class);
|
||||
|
||||
private static final String PREFERENCE_KEY_PATH_JMBE_LIBRARY = "path.jmbe.library.1.0.0";
|
||||
private static final String PREFERENCE_KEY_PATH_ALERT_LIBRARY_REQUIRED = "alert.jmbe.required";
|
||||
private final Pattern VERSION_PATTERN = Pattern.compile(".*jmbe-(\\d{1,5}.\\d{1,5}.\\d{1,5}\\w*)\\.jar");
|
||||
private Path mPathJmbeLibrary;
|
||||
private Boolean mAlertIfMissingLibraryRequired;
|
||||
|
||||
/**
|
||||
* Constructs this preference with an update listener
|
||||
@@ -60,6 +66,23 @@ public class JmbeLibraryPreference extends Preference
|
||||
return PreferenceType.JMBE_LIBRARY;
|
||||
}
|
||||
|
||||
public Version getCurrentVersion()
|
||||
{
|
||||
Path path = getPathJmbeLibrary();
|
||||
|
||||
if(path != null)
|
||||
{
|
||||
Matcher m = VERSION_PATTERN.matcher(path.toString());
|
||||
|
||||
if(m.matches())
|
||||
{
|
||||
return Version.fromString(m.group(1));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Path to the JMBE audio codec library
|
||||
*/
|
||||
@@ -73,6 +96,14 @@ public class JmbeLibraryPreference extends Preference
|
||||
return mPathJmbeLibrary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a path to a JMBE library is setup (ie non-null).
|
||||
*/
|
||||
public boolean hasJmbeLibraryPath()
|
||||
{
|
||||
return getPathJmbeLibrary() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path to the JMBE library
|
||||
*/
|
||||
@@ -93,6 +124,30 @@ public class JmbeLibraryPreference extends Preference
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the user should be alerted when the JMBE library is not setup, but required for decoding.
|
||||
*/
|
||||
public boolean getAlertIfMissingLibraryRequired()
|
||||
{
|
||||
if(mAlertIfMissingLibraryRequired == null)
|
||||
{
|
||||
mAlertIfMissingLibraryRequired = mPreferences.getBoolean(PREFERENCE_KEY_PATH_ALERT_LIBRARY_REQUIRED, true);
|
||||
}
|
||||
|
||||
return mAlertIfMissingLibraryRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value for alerting when the library is required for decoding but the library is not currently setup.
|
||||
* @param alert true if the user should be alerted when the library is not setup, but required for decoding.
|
||||
*/
|
||||
public void setAlertIfMissingLibraryRequired(boolean alert)
|
||||
{
|
||||
mAlertIfMissingLibraryRequired = alert;
|
||||
mPreferences.putBoolean(PREFERENCE_KEY_PATH_ALERT_LIBRARY_REQUIRED, mAlertIfMissingLibraryRequired);
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path stored in preferences and referenced by the key argument if it exists, otherwise returns the
|
||||
* default path.
|
||||
|
||||
@@ -42,6 +42,7 @@ public class DirectoryPreference extends Preference
|
||||
private static final String DIRECTORY_APPLICATION_ROOT = "SDRTrunk";
|
||||
private static final String DIRECTORY_APPLICATION_LOG = "logs";
|
||||
private static final String DIRECTORY_EVENT_LOG = "event_logs";
|
||||
private static final String DIRECTORY_JMBE = "jmbe";
|
||||
private static final String DIRECTORY_PLAYLIST = "playlist";
|
||||
private static final String DIRECTORY_RECORDING = "recordings";
|
||||
private static final String DIRECTORY_SCREEN_CAPTURE = "screen_captures";
|
||||
@@ -50,6 +51,7 @@ public class DirectoryPreference extends Preference
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_APPLICATION_ROOT = "directory.application.root";
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_APPLICATION_LOGS = "directory.application.logs";
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_EVENT_LOGS = "directory.event.logs";
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_JMBE = "directory.jmbe";
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_PLAYLIST = "directory.playlist";
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_RECORDING = "directory.recording";
|
||||
private static final String PREFERENCE_KEY_DIRECTORY_SCREEN_CAPTURE = "directory.screen.capture";
|
||||
@@ -58,6 +60,7 @@ public class DirectoryPreference extends Preference
|
||||
private Path mDirectoryApplicationRoot;
|
||||
private Path mDirectoryApplicationLogs;
|
||||
private Path mDirectoryEventLogs;
|
||||
private Path mDirectoryJmbe;
|
||||
private Path mDirectoryPlaylist;
|
||||
private Path mDirectoryRecording;
|
||||
private Path mDirectoryScreenCapture;
|
||||
@@ -115,6 +118,7 @@ public class DirectoryPreference extends Preference
|
||||
{
|
||||
mDirectoryApplicationLogs = null;
|
||||
mDirectoryEventLogs = null;
|
||||
mDirectoryJmbe = null;
|
||||
mDirectoryPlaylist = null;
|
||||
mDirectoryRecording = null;
|
||||
mDirectoryScreenCapture = null;
|
||||
@@ -204,6 +208,40 @@ public class DirectoryPreference extends Preference
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to the folder for storing the JMBE audio library
|
||||
*/
|
||||
public Path getDirectoryJmbe()
|
||||
{
|
||||
if(mDirectoryJmbe == null)
|
||||
{
|
||||
mDirectoryJmbe = getPath(PREFERENCE_KEY_DIRECTORY_JMBE, getDefaultJmbeDirectory());
|
||||
createDirectory(mDirectoryJmbe);
|
||||
}
|
||||
|
||||
return mDirectoryJmbe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path to the JMBE folder
|
||||
*/
|
||||
public void setDirectoryJmbe(Path path)
|
||||
{
|
||||
mDirectoryJmbe = path;
|
||||
mPreferences.put(PREFERENCE_KEY_DIRECTORY_JMBE, path.toString());
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a stored playlist directory preference so that the default path can be used again
|
||||
*/
|
||||
public void resetDirectoryJmbe()
|
||||
{
|
||||
mPreferences.remove(PREFERENCE_KEY_DIRECTORY_JMBE);
|
||||
mDirectoryJmbe = null;
|
||||
notifyPreferenceUpdated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Path to the folder for storing playlist
|
||||
*/
|
||||
@@ -364,6 +402,14 @@ public class DirectoryPreference extends Preference
|
||||
return getDirectoryApplicationRoot().resolve(DIRECTORY_EVENT_LOG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default JMBE directory
|
||||
*/
|
||||
public Path getDefaultJmbeDirectory()
|
||||
{
|
||||
return getDirectoryApplicationRoot().resolve(DIRECTORY_JMBE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default playlist directory
|
||||
*/
|
||||
|
||||
76
src/main/java/io/github/dsheirer/util/FileUtil.java
Normal file
76
src/main/java/io/github/dsheirer/util/FileUtil.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* File Utilities
|
||||
*/
|
||||
public class FileUtil
|
||||
{
|
||||
/**
|
||||
* Recursively searches for the named file starting in the specified directory.
|
||||
* @param directory to search for the file
|
||||
* @return path to the file or null if the file can't be found
|
||||
* @throws IOException if there is a file system error or if the file is not found
|
||||
*/
|
||||
public static Path findFile(Path directory, String name) throws IOException
|
||||
{
|
||||
if(Files.isDirectory(directory))
|
||||
{
|
||||
DirectoryStream<Path> stream = Files.newDirectoryStream(directory);
|
||||
Iterator<Path> it = stream.iterator();
|
||||
Path path = null;
|
||||
while(it.hasNext())
|
||||
{
|
||||
path = it.next();
|
||||
|
||||
if(Files.isDirectory(path))
|
||||
{
|
||||
Path candidate = findFile(path, name);
|
||||
|
||||
if(candidate != null)
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(path.endsWith(name))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException("A directory required for this method [" +
|
||||
(directory != null ? directory.toString() : "null") + "]");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
101
src/main/java/io/github/dsheirer/util/OSType.java
Normal file
101
src/main/java/io/github/dsheirer/util/OSType.java
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
|
||||
package io.github.dsheirer.util;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
|
||||
public enum OSType
|
||||
{
|
||||
LINUX_32,
|
||||
LINUX_64,
|
||||
OSX_32,
|
||||
OSX_64,
|
||||
WINDOWS_32,
|
||||
WINDOWS_64,
|
||||
UNKNOWN;
|
||||
|
||||
public static EnumSet<OSType> WINDOWS_TYPES = EnumSet.of(WINDOWS_32, WINDOWS_64);
|
||||
public static EnumSet<OSType> LINUX_TYPES = EnumSet.of(LINUX_32, LINUX_64, OSX_32, OSX_64);
|
||||
|
||||
/**
|
||||
* Indicates if this enumeration entry is a Windows type
|
||||
*/
|
||||
public boolean isWindows()
|
||||
{
|
||||
return WINDOWS_TYPES.contains(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this enumeration entry is a Linux type
|
||||
*/
|
||||
public boolean isLinux()
|
||||
{
|
||||
return LINUX_TYPES.contains(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the current host operating system and architecture
|
||||
*/
|
||||
public static OSType getCurrentOSType()
|
||||
{
|
||||
String os = System.getProperty("os.name", "unknown").toLowerCase(Locale.ENGLISH);
|
||||
String arch = System.getProperty("os.arch");
|
||||
|
||||
if(os.contains("win"))
|
||||
{
|
||||
if(arch.contains("64"))
|
||||
{
|
||||
return OSType.WINDOWS_64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OSType.WINDOWS_32;
|
||||
}
|
||||
}
|
||||
|
||||
if(os.contains("mac") || os.contains("darwin"))
|
||||
{
|
||||
if(arch.contains("64"))
|
||||
{
|
||||
return OSType.OSX_64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OSType.OSX_32;
|
||||
}
|
||||
}
|
||||
|
||||
if(os.contains("nux") || os.contains("nix") || os.contains("aix"))
|
||||
{
|
||||
if(arch.contains("64"))
|
||||
{
|
||||
return OSType.LINUX_64;
|
||||
}
|
||||
else
|
||||
{
|
||||
return OSType.LINUX_32;
|
||||
}
|
||||
}
|
||||
|
||||
return OSType.UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
158
src/main/java/io/github/dsheirer/util/ZipUtility.java
Normal file
158
src/main/java/io/github/dsheirer/util/ZipUtility.java
Normal file
@@ -0,0 +1,158 @@
|
||||
package io.github.dsheirer.util;
|
||||
|
||||
import org.rauschig.jarchivelib.ArchiveFormat;
|
||||
import org.rauschig.jarchivelib.Archiver;
|
||||
import org.rauschig.jarchivelib.ArchiverFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* This utility compresses a list of files to standard ZIP format file.
|
||||
* It is able to compress all sub files and sub directories, recursively.
|
||||
*
|
||||
* @author www.codejava.net
|
||||
*/
|
||||
public class ZipUtility
|
||||
{
|
||||
/**
|
||||
* A constants for buffer size used to read/write data
|
||||
*/
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
/**
|
||||
* Compresses a list of files to a destination zip file
|
||||
*
|
||||
* @param listFiles A collection of files and directories
|
||||
* @param destZipFile The path of the destination zip file
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void zip(List<File> listFiles, String destZipFile) throws FileNotFoundException,
|
||||
IOException
|
||||
{
|
||||
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destZipFile));
|
||||
for(File file : listFiles)
|
||||
{
|
||||
if(file.isDirectory())
|
||||
{
|
||||
zipDirectory(file, file.getName(), zos);
|
||||
}
|
||||
else
|
||||
{
|
||||
zipFile(file, zos);
|
||||
}
|
||||
}
|
||||
zos.flush();
|
||||
zos.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses files represented in an array of paths
|
||||
*
|
||||
* @param files a String array containing file paths
|
||||
* @param destZipFile The path of the destination zip file
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void zip(String[] files, String destZipFile) throws FileNotFoundException, IOException
|
||||
{
|
||||
List<File> listFiles = new ArrayList<File>();
|
||||
|
||||
for(int i = 0; i < files.length; i++)
|
||||
{
|
||||
listFiles.add(new File(files[i]));
|
||||
}
|
||||
|
||||
zip(listFiles, destZipFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a directory to the current zip output stream
|
||||
*
|
||||
* @param folder the directory to be added
|
||||
* @param parentFolder the path of parent directory
|
||||
* @param zos the current zip output stream
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void zipDirectory(File folder, String parentFolder, ZipOutputStream zos) throws
|
||||
FileNotFoundException, IOException
|
||||
{
|
||||
if(folder == null || folder.listFiles() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(File file : folder.listFiles())
|
||||
{
|
||||
if(file.exists())
|
||||
{
|
||||
if(file.isDirectory())
|
||||
{
|
||||
zipDirectory(file, parentFolder + "/" + file.getName(), zos);
|
||||
continue;
|
||||
}
|
||||
|
||||
zos.putNextEntry(new ZipEntry(parentFolder + "/" + file.getName()));
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
long bytesRead = 0;
|
||||
byte[] bytesIn = new byte[BUFFER_SIZE];
|
||||
int read = 0;
|
||||
while((read = bis.read(bytesIn)) != -1)
|
||||
{
|
||||
zos.write(bytesIn, 0, read);
|
||||
bytesRead += read;
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to the current zip output stream
|
||||
*
|
||||
* @param file the file to be added
|
||||
* @param zos the current zip output stream
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void zipFile(File file, ZipOutputStream zos) throws FileNotFoundException, IOException
|
||||
{
|
||||
zos.putNextEntry(new ZipEntry(file.getName()));
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
long bytesRead = 0;
|
||||
byte[] bytesIn = new byte[BUFFER_SIZE];
|
||||
int read = 0;
|
||||
while((read = bis.read(bytesIn)) != -1)
|
||||
{
|
||||
zos.write(bytesIn, 0, read);
|
||||
bytesRead += read;
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unzips the specified file into the directory where it's located
|
||||
*
|
||||
* @param zipFile to unzip
|
||||
* @return path to where the file was unzipped.
|
||||
* @throws IOException if there are errors unzipping
|
||||
*/
|
||||
public static Path unzip(Path zipFile) throws IOException
|
||||
{
|
||||
Path parent = zipFile.getParent();
|
||||
Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.ZIP);
|
||||
archiver.extract(zipFile.toFile(), parent.toFile());
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user