Class MediaEditorGUI

java.lang.Object
java.awt.Component
org.emrick.project.MediaEditorGUI
All Implemented Interfaces:
ImageObserver, MenuContainer, Serializable, DevModeHost, EffectListener, RFTriggerListener, FootballFieldListener, ImportListener, LEDConfigListener, ReplaceFilesListener, RequestCompleteListener, RFSignalListener, ScrubBarListener, SelectListener, SyncListener, TimelineListener, UserAuthListener

Main class of Emrick Designer. Contains all GUI elements and logic for light show design and Emrick board interaction
See Also:
  • Field Details

  • Constructor Details

    • MediaEditorGUI

      public MediaEditorGUI(String file)
      Constructor for MediaEditorGUI
      Parameters:
      file - - Used when starting the application via opening a file via an associated type. Otherwise, this can be left as an empty string.
  • Method Details

    • main

      public static void main(String[] args)
      Main method of Emrick Designer.
      Parameters:
      args - - Only used when opening the application via an associated file type rather than an executable
    • getPlaybackTimerTimeByCounts

      private long getPlaybackTimerTimeByCounts()
      Calculates and returns the frame length in milliseconds
      Returns:
      - Time in milliseconds the timer should wait between frames
    • deleteDirectoryContents

      private static void deleteDirectoryContents(File dir)
      Recursively deletes everything inside dir. Files that can't be deleted (e.g. audio still held open by another running Emrick Designer) are skipped rather than retried, so this always finishes.
    • setupLookAndFeel

      private static void setupLookAndFeel()
      Sets up the look and feel of the application based on the user's OS theme.
    • createAndShowGUI

      private void createAndShowGUI()
      Builds all major GUI elements and adds them to the main frame. This method should be called on startup and on project loading when another project is already loaded.
    • buildDesignerGUI

      private void buildDesignerGUI()
    • savePropertiesToFile

      private void savePropertiesToFile(Properties props, File configFile, String dataDir, String packetsDir, String csvFile, String showToken, String verificationColor, String marcherLabel)
    • deleteDirectory

      private boolean deleteDirectory(File directoryToBeDeleted)
      Recursively empties and deletes the specified file/directory.
      Parameters:
      directoryToBeDeleted - - File or directory that should be emptied and/or deleted
      Returns:
      true - if the directory was deleted successfully. false - otherwise
    • getEffectOptionsButton

      private JComponent getEffectOptionsButton()
      Initializes the Effect Options button and the effects popup menu and returns the Effect Options button.
      Returns:
      JButton button that displays a popup menu with all the effect options when pressed
    • createEffectAtCurrentTime

      private void createEffectAtCurrentTime(EffectList effectType)
      Helper method to create a 16-count effect of the given type at the current timeline position
    • openPreviewEffectWindow

      private void openPreviewEffectWindow()
      Opens the Outlook-style "Preview Effect" window: a fixed list of effect types on the left, and the selected type's edit panel (with a timeline-box preview above it) filling the rest. Its built-in "Preview on Hardware" button sends live packets to a connected Receiver. Works even without a project loaded (falls back to a synthetic 120bpm timeline); Grid is excluded since it has no single-strip preview.
    • createDefaultEffectForPreview

      private Effect createDefaultEffectForPreview(EffectList effectType)
      Builds a fresh default effect of the given type, anchored at the current timeline position.
    • showPreviewColorDialog

      private void showPreviewColorDialog()
      Opens a color-chooser dialog that holds a solid color on a connected Receiver indefinitely (until a new color is sent, or the dialog is closed), replacing the old one-shot Check Color.
    • comPortPrompt

      public SerialTransmitter comPortPrompt(String type)
      Used to get a Serial Transmitter object. Now uses the hardware status indicator instead of prompting the user each time.
      Parameters:
      type - The type of hardware that should be detected ("Transmitter" or "Receiver").
      Returns:
      A SerialTransmitter object for the specified type. If no hardware of the requested type is available, this method returns null.
    • portsHeldByDeveloperMode

      private String portsHeldByDeveloperMode()
      Returns:
      a note naming any units Developer Mode currently has open, or "" if none
    • comPortPromptFlow

      public SerialTransmitter comPortPromptFlow()
    • oldComPortPrompt

      private SerialTransmitter oldComPortPrompt(String type)
      Legacy method for hardware detection - kept as fallback
    • removeFlowViewer

      private void removeFlowViewer()
      Removes the flow viewer from the main content panel and restores the run menu to be used again
    • stopServer

      private void stopServer()
      Stops the currently running web server, restores the run menu to be used again, and cleans the filesystem of any files created by the web server
    • runServer

      private void runServer(String path)
      Prompts the user for information and then starts a web server using this information
      Parameters:
      path - A path to the .pkt file whose contents should be served by the web server.
    • updateProgressLabel

      private void updateProgressLabel(JLabel label, Set<Integer> newlyProgrammed, Set<Integer> previouslyProgrammed, int totalBoards)
    • loadProject

      private void loadProject(File path)
      Loads a new .emrick file to the viewport to be edited.
      Parameters:
      path - Path pointing to the intended .emrick file
    • loadProjectData

      private MediaEditorGUI.LoadedProjectData loadProjectData(File projectPath, Consumer<ThemedLoadingDialog.StatusUpdate> progressConsumer)
    • prepareLoadedProjectDataForUi

      private void prepareLoadedProjectDataForUi(MediaEditorGUI.LoadedProjectData loadedProjectData, Consumer<ThemedLoadingDialog.StatusUpdate> progressConsumer)
    • prepareDrillForLoadedProject

      private void prepareDrillForLoadedProject(Drill drill, Consumer<ThemedLoadingDialog.StatusUpdate> progressConsumer)
    • startPhasedProjectApply

      private void startPhasedProjectApply(MediaEditorGUI.LoadedProjectData loadedProjectData, ThemedLoadingDialog loadingDialog)
    • applyLoadedProject

      private void applyLoadedProject(MediaEditorGUI.LoadedProjectData loadedProjectData)
    • applyLoadedProjectPhaseOne

      private void applyLoadedProjectPhaseOne(MediaEditorGUI.LoadedProjectData loadedProjectData)
    • applyLoadedProjectPhaseTwo

      private void applyLoadedProjectPhaseTwo(MediaEditorGUI.LoadedProjectData loadedProjectData)
    • timeSyncCoversDrillSets

      private boolean timeSyncCoversDrillSets(ArrayList<SyncTimeGUI.Pair> sync)
      Checks that a saved time sync has a duration for every set TimeManager will look up (all but the last). A sync saved against a different drill would otherwise crash the load, so the project is opened un-synced instead and the user is told to re-sync.
    • applyLoadedProjectPhaseThree

      private void applyLoadedProjectPhaseThree()
    • recoverGridEffectState

      private void recoverGridEffectState()
    • recoverGridEffectState

      private void recoverGridEffectState(Drill drill)
    • recoverGridEffectState

      private void recoverGridEffectState(Drill drill, Consumer<ThemedLoadingDialog.StatusUpdate> progressConsumer)
    • publishLoading

      private void publishLoading(Consumer<ThemedLoadingDialog.StatusUpdate> progressConsumer, String title, String detail)
    • concatenateProject

      private void concatenateProject(File path)
    • getMovementIndex

      private int getMovementIndex()
    • buildScrubBarPanel

      private void buildScrubBarPanel()
      Loads the ScrubBarGUI Panel if it has not been created, or refreshes it if it already exists.
    • onMultiSelect

      public void onMultiSelect(HashSet<Integer> labels, HashSet<String> symbols)
      Specified by:
      onMultiSelect in interface SelectListener
    • onGroupSelection

      public void onGroupSelection(LEDStrip[] ledStrips)
      Specified by:
      onGroupSelection in interface SelectListener
    • ctrlGroupSelection

      public void ctrlGroupSelection(LEDStrip[] ledStrips)
      Specified by:
      ctrlGroupSelection in interface SelectListener
    • onSaveGroup

      public LEDStrip[] onSaveGroup()
      Specified by:
      onSaveGroup in interface SelectListener
    • onUpdateGroup

      public void onUpdateGroup()
      Specified by:
      onUpdateGroup in interface SelectListener
    • exportCsvFileForPerformerDeviceIDs

      private void exportCsvFileForPerformerDeviceIDs(File selectedFile)
      Builds and exports a csv file containing configuration data for led strips and performers

      Format:

      The first line contains headers and the last element contains the expected number of led strips.

      A new performer starts on a new line where its label (Ex. "R31") is written as the first element

      Below each performer label will be a list of all of this performer's led strips, each line beginning with an empty element. The led strips lines will contain their label, id, and a set of configuration data.

      Ex. ",226,R31L,50,12,6,-6,-6"

      Parameters:
      selectedFile - The desired file location to write the csv file.
    • exportBoardChecklistWorkbook

      private void exportBoardChecklistWorkbook(File selectedFile)
    • getOrCreateRow

      private org.apache.poi.ss.usermodel.Row getOrCreateRow(org.apache.poi.ss.usermodel.Sheet sheet, int rowIndex)
    • getSectionFromBoardLabel

      private String getSectionFromBoardLabel(String boardLabel)
    • isGdsUnit

      private boolean isGdsUnit(String boardLabel)
    • hexToRgbBytes

      private byte[] hexToRgbBytes(String hex)
    • createChecklistCellStyle

      private org.apache.poi.ss.usermodel.CellStyle createChecklistCellStyle(org.apache.poi.ss.usermodel.Workbook workbook, org.apache.poi.ss.usermodel.BorderStyle left, org.apache.poi.ss.usermodel.BorderStyle right, org.apache.poi.ss.usermodel.BorderStyle top, org.apache.poi.ss.usermodel.BorderStyle bottom)
    • createBorderStyle

      private org.apache.poi.ss.usermodel.CellStyle createBorderStyle(org.apache.poi.ss.usermodel.Workbook workbook, org.apache.poi.ss.usermodel.BorderStyle left, org.apache.poi.ss.usermodel.BorderStyle right, org.apache.poi.ss.usermodel.BorderStyle top, org.apache.poi.ss.usermodel.BorderStyle bottom)
    • applyDefaultLEDConfiguration

      private void applyDefaultLEDConfiguration()
      Applies a default led configuration to all performers
    • applyDefaultLEDConfiguration

      private void applyDefaultLEDConfiguration(Drill drill)
    • parseCsvFileForPerformerDeviceIDs

      private void parseCsvFileForPerformerDeviceIDs(File inputFile)
      Imports a configuration csv file and applies the config to an open project.
      Parameters:
      inputFile - csv configuration file
    • parseCsvFileForPerformerDeviceIDs

      private void parseCsvFileForPerformerDeviceIDs(Drill drill, File inputFile)
    • openProjectDialog

      private void openProjectDialog()
      Opens a prompt for the user to select a project to open.
    • enterDeveloperMode

      private void enterDeveloperMode()
      Shows Developer Mode in place of the designer view, under the same menu bar. The project stays loaded so its board list can be used for lookups, and File > Open still works while Developer Mode is showing.
    • exitDeveloperMode

      public void exitDeveloperMode()
      Specified by:
      exitDeveloperMode in interface DevModeHost
    • isShowRunning

      private boolean isShowRunning()
      Returns:
      true while a show is being run from the Run menu
    • yieldDeveloperModeForShow

      private void yieldDeveloperModeForShow()
      Running a show takes priority over Developer Mode: close it (its features let go of the transmitter and any other ports) and bring back the designer view before the show starts. Receivers being flashed keep flashing.
    • showDesignerView

      private void showDesignerView()
      Puts the designer view back in place of Developer Mode (after Developer Mode has been shut down).
    • syncDeveloperModeItem

      private void syncDeveloperModeItem()
    • getFrame

      public JFrame getFrame()
      Specified by:
      getFrame in interface DevModeHost
    • getLedStrips

      public List<LEDStrip> getLedStrips()
      Specified by:
      getLedStrips in interface DevModeHost
      Returns:
      the open project's LED strips (board ID, label, LED count), or an empty list if no project is open
    • openProjectForDevMode

      public void openProjectForDevMode()
      Description copied from interface: DevModeHost
      Leaves Developer Mode, lets the user open a project, and comes back to Developer Mode once it's loaded.
      Specified by:
      openProjectForDevMode in interface DevModeHost
    • concatenateDialog

      private void concatenateDialog()
    • hasUnsavedChanges

      private boolean hasUnsavedChanges()
      Returns:
      true if the open project differs from what was last saved or loaded, or has never been saved. Compares the actual project content, so edits that were undone, and changes outside the undo history (RF triggers, time sync, LED setup, groups), are judged correctly.
    • markProjectSaved

      private void markProjectSaved()
      Records the current project content as the saved state.
    • currentProjectFingerprint

      private String currentProjectFingerprint()
      Hashes the project's show content, streamed so large shows aren't held in memory. Uses fingerprintGson so viewing the show (scrubbing, exporting packets) doesn't count as a change.
    • createFingerprintGson

      private static com.google.gson.Gson createFingerprintGson(com.google.gson.Gson projectGson)
      Project serializer for change detection. It ignores state that changes just from viewing the show: performer positions (updated while scrubbing) and the order of each strip's effects (packet export sorts them in place; playback and export only depend on effect times).
    • saveProjectDialog

      private void saveProjectDialog()
      Attempts to save the project to a file. If the currently open project is a new project, the user will be prompted to specify a save location before the project is saved.
    • saveAsProjectDialog

      private void saveAsProjectDialog()
      Prompts the user for a location to save the current project.
    • onBeginImport

      public void onBeginImport()
      Specified by:
      onBeginImport in interface ImportListener
    • onImport

      public void onImport()
      Specified by:
      onImport in interface ImportListener
    • onFileSelect

      public void onFileSelect(ArrayList<File> archivePaths, File csvFile)
      Specified by:
      onFileSelect in interface ImportListener
    • onAudioImport

      public void onAudioImport(ArrayList<File> audioFiles)
      Specified by:
      onAudioImport in interface ImportListener
    • onConcatAudioImport

      public void onConcatAudioImport(ArrayList<File> audioFiles)
      Specified by:
      onConcatAudioImport in interface ImportListener
    • onDrillImport

      public void onDrillImport(String drill)
      Specified by:
      onDrillImport in interface ImportListener
    • applyImportedDrill

      private void applyImportedDrill(Drill importedDrill)
    • runOnEdtAndWait

      private void runOnEdtAndWait(Runnable runnable)
    • rebuildPageTabCounts

      private void rebuildPageTabCounts()
      Rebuilds the map of set labels to set start counts that is used in ScrubBarGUI.
    • onSync

      public void onSync(ArrayList<SyncTimeGUI.Pair> times, float startDelay)
      Specified by:
      onSync in interface SyncListener
    • setupEffectView

      private void setupEffectView(ArrayList<Integer> ids)
      Initializes the effect panel and its dependencies
      Parameters:
      ids - List of effect ids
    • onPlay

      public boolean onPlay()
      Specified by:
      onPlay in interface ScrubBarListener
    • onPause

      public boolean onPause()
      Specified by:
      onPause in interface ScrubBarListener
    • onScrub

      public long onScrub()
      Specified by:
      onScrub in interface ScrubBarListener
    • onTimeChange

      public void onTimeChange(long time)
      Specified by:
      onTimeChange in interface ScrubBarListener
    • onSetChange

      public void onSetChange(int setIndex)
      Specified by:
      onSetChange in interface ScrubBarListener
    • playAudioFromCorrectPosition

      private void playAudioFromCorrectPosition()
      Begin playing audio in sync with the drill playback
    • getPrevAudioPlayerDurations

      public long getPrevAudioPlayerDurations(int index)
    • onSpeedChange

      public void onSpeedChange(float playbackSpeed)
      Specified by:
      onSpeedChange in interface ScrubBarListener
    • onUserLoggedIn

      public void onUserLoggedIn(String username)
      Specified by:
      onUserLoggedIn in interface UserAuthListener
    • updateFrameTitle

      private void updateFrameTitle()
      Shows the name of the currently open project file in the window title bar. Call whenever emrickPath or the open project changes.
    • showEffectBeforeFirstTriggerError

      private void showEffectBeforeFirstTriggerError()
      Display an error message to the user that indicates an RF Trigger has not been placed yet.
    • onCreateEffect

      public void onCreateEffect(Effect effect)
      Specified by:
      onCreateEffect in interface EffectListener
    • onUpdateEffect

      public void onUpdateEffect(Effect oldEffect, Effect newEffect)
      Specified by:
      onUpdateEffect in interface EffectListener
    • onDeleteEffect

      public void onDeleteEffect(Effect effect)
      Specified by:
      onDeleteEffect in interface EffectListener
    • onUpdateEffectPanel

      public void onUpdateEffectPanel(Effect effect, boolean isNew, int index)
      Specified by:
      onUpdateEffectPanel in interface EffectListener
    • onChangeSelectionMode

      public void onChangeSelectionMode(boolean isInnerSelect, HashSet<LEDStrip> strips)
      Specified by:
      onChangeSelectionMode in interface EffectListener
    • onInnerSelectionRequired

      public HashSet<LEDStrip> onInnerSelectionRequired()
      Specified by:
      onInnerSelectionRequired in interface EffectListener
    • onSelectionRequired

      public HashSet<LEDStrip> onSelectionRequired()
      Specified by:
      onSelectionRequired in interface EffectListener
    • onTimeRequired

      public TimeManager onTimeRequired()
      Specified by:
      onTimeRequired in interface EffectListener
    • getOrCreateDefaultPreviewTimeManager

      private TimeManager getOrCreateDefaultPreviewTimeManager()
      A synthetic 120bpm (0.5s/count) timeline, used only when previewing effects with no project loaded.
    • onPerformerSelect

      public void onPerformerSelect()
      Specified by:
      onPerformerSelect in interface FootballFieldListener
    • onPerformerDeselect

      public void onPerformerDeselect()
      Specified by:
      onPerformerDeselect in interface FootballFieldListener
    • onTimelineScrub

      public void onTimelineScrub(double count)
      Description copied from interface: TimelineListener
      Called when the timeline is scrubbed to a specific count
      Specified by:
      onTimelineScrub in interface TimelineListener
      Parameters:
      count - The count position that was scrubbed to
    • onCreateRFTrigger

      public void onCreateRFTrigger(RFTrigger rfTrigger)
      Specified by:
      onCreateRFTrigger in interface RFTriggerListener
    • onUpdateRFTrigger

      public void onUpdateRFTrigger(RFTrigger rfTrigger, int count)
      Specified by:
      onUpdateRFTrigger in interface RFTriggerListener
    • onDeleteRFTrigger

      public void onDeleteRFTrigger(int count)
      Specified by:
      onDeleteRFTrigger in interface RFTriggerListener
    • onPressRFTrigger

      public void onPressRFTrigger(RFTrigger rfTrigger)
      Specified by:
      onPressRFTrigger in interface RFTriggerListener
    • onResizeBackground

      public void onResizeBackground()
      Specified by:
      onResizeBackground in interface FootballFieldListener
    • getFrameRate

      public double getFrameRate()
      Specified by:
      getFrameRate in interface FootballFieldListener
    • isPlaying

      public boolean isPlaying()
      Specified by:
      isPlaying in interface FootballFieldListener
    • onPressEffect

      public void onPressEffect(Effect effect)
      Specified by:
      onPressEffect in interface EffectListener
    • onPreviewOnHardware

      public void onPreviewOnHardware(Effect effect)
      Description copied from interface: EffectListener
      Sends the given effect to a connected Receiver board for a live, on-hardware preview.
      Specified by:
      onPreviewOnHardware in interface EffectListener
    • playPreviewSegment

      private void playPreviewSegment(MediaEditorGUI.PreviewPlan plan, int index)
      Sends one segment of a (possibly multi-segment, e.g. Wave/Ripple) previewed effect, then schedules the next segment to fire once this one's own duration elapses. After the last segment, schedules an automatic stop instead of requiring the "Stop Preview" button.
    • onStopHardwarePreview

      public void onStopHardwarePreview()
      Description copied from interface: EffectListener
      Returns a connected Receiver's LEDs to idle and exits its preview mode, if it was previewing.
      Specified by:
      onStopHardwarePreview in interface EffectListener
    • onPreviewColorOnHardware

      public void onPreviewColorOnHardware(Color color)
      Description copied from interface: EffectListener
      Holds a solid color on a connected Receiver indefinitely, for quick verification while picking colors.
      Specified by:
      onPreviewColorOnHardware in interface EffectListener
    • buildPreviewPlan

      private MediaEditorGUI.PreviewPlan buildPreviewPlan(Effect effect)
      Builds the ordered list of packet segments for previewing the given effect on hardware. Simple effect types generate exactly one segment; spatial/generated types (e.g. Wave) can decompose into several chained segments per strip, which are all collected here (sorted by start time) so the full animation plays instead of just its first slice. For spatial types, the drill's performer "1" (N1) in the first Set stands in for the connected Receiver. If no project/drill is loaded, spatial resolution is skipped and the effect is previewed directly, so hardware preview still works without a show open.
    • findN1LedStrip

      private LEDStrip findN1LedStrip(Drill drill)
    • updateEffectViewPanel

      private void updateEffectViewPanel(EffectList effectType, Effect effect)
      Update the effect panel to display the currently selected effect
      Parameters:
      effectType - - The type of effect that is currently selected.
    • replaceEffectView

      private void replaceEffectView(JComponent center, JComponent south)
      Atomically replace the effect view center and south components so only the desired panels are visible. Pass null for either argument to omit that region.
    • replaceMainView

      private void replaceMainView(JComponent center, JComponent south)
      Atomically replace the main content center and south components so only the desired panels are visible. Pass null for either argument to omit that region.
    • buildWelcomePanel

      private JPanel buildWelcomePanel(MediaEditorGUI mediaEditorGUI)
      Build the welcome panel displayed when no project is loaded. Contains a clickable/open control and a list of recently opened projects.
    • toHex

      private static String toHex(Color c)
    • loadRecentProjects

      private List<File> loadRecentProjects()
      Load recent projects from user folder. Only returns existing files.
    • saveRecentProjects

      private void saveRecentProjects(List<File> list)
    • addToRecentProjects

      private void addToRecentProjects(File f)
    • updateTimelinePanel

      private void updateTimelinePanel()
      Update the timeline panel to show data relevant to the currently selected performers.
    • saveProject

      private void saveProject(File path, ArrayList<File> archivePaths)
      Save the current project to a .emrick file.
      Parameters:
      path - The file location to save the project.
      archivePaths - The locations of the .3dz files in user files when the project is loaded.
    • buildProjectFile

      private ProjectFile buildProjectFile(ArrayList<File> archivePaths)
      Builds the serializable project exactly as it is written to the .emrick file.
    • timeBeforeEffect

      private long timeBeforeEffect(int index, Effect e, ArrayList<Effect> effects, Long[] timesMS)
      Calculates the time between the end of the previous effect/RF Trigger and the start of the current effect.
      Parameters:
      index - Current RF Trigger index
      e - Effect to find the time before
      effects - List of effects on the relevant led strip
      timesMS - A list of times in milliseconds that RF Triggers occur
      Returns:
      The time in milliseconds between the current effect and the previous effect/RF Trigger.
    • timeAfterEffect

      private long timeAfterEffect(int index, Effect e, ArrayList<Effect> effects, Long[] timesMS)
      Calculates the time between the end of the current effect and the start of the next effect/RF Trigger.
      Parameters:
      index - Current RF Trigger index
      e - Effect to find the time before
      effects - List of effects on the relevant led strip
      timesMS - A list of times in milliseconds that RF Triggers occur
      Returns:
      The time in milliseconds between the current effect and the next effect/RF Trigger.
    • getEffectTriggerIndex

      private int getEffectTriggerIndex(Effect e, Long[] timesMS)
      Calculates the index of the RF Trigger immediately before the relevant effect.
      Parameters:
      e - The relevant effect.
      timesMS - A list of times in milliseconds that RF Triggers occur
      Returns:
      The index of the RF Trigger immediately before the relevant effect.
    • exportPackets

      private void exportPackets(File path)
      Multithreaded export of firmware-readable packet data to a .pkt file.
      Parameters:
      path - Location to write .pkt file.
    • writeSysMsg

      private void writeSysMsg(String msg)
      Writes a system message in the top right of the screen
      Parameters:
      msg - Message to be written
    • onRFSignal

      public void onRFSignal(int i)
      Specified by:
      onRFSignal in interface RFSignalListener
    • onRequestComplete

      public void onRequestComplete(int id)
      Specified by:
      onRequestComplete in interface RequestCompleteListener
    • onExitConfig

      public void onExitConfig()
      Specified by:
      onExitConfig in interface LEDConfigListener
    • onNewFileSelect

      public boolean onNewFileSelect(File drill, File archive)
      Specified by:
      onNewFileSelect in interface ReplaceFilesListener
    • getAudioPlayers

      public ArrayList<AudioPlayer> getAudioPlayers()
      Get audio player
      Returns:
      AudioPlayer object