package cz.fidentis.analyst.project; import cz.fidentis.analyst.faceState.FaceStatePanel; import cz.fidentis.analyst.core.FaceTab; import cz.fidentis.analyst.core.ProgressDialog; import cz.fidentis.analyst.face.HumanFace; import cz.fidentis.analyst.filter.FilterPanel; import cz.fidentis.analyst.scene.Camera; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTable; import javax.swing.SwingWorker; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.filechooser.FileNameExtensionFilter; import org.openide.filesystems.FileChooserBuilder; import org.openide.util.Exceptions; /** * * @author Matej Kovar */ public class ProjectPanel extends JPanel { public static final String SAVE_CURRENT_PROJECT_TITLE = "Save current project"; public static final String SAVE_NEW_PROJECT_TITLE = "Save new project"; private Project project; private static List<FaceTab> tabs = new ArrayList<>(); private ModelsTableModel model = new ModelsTableModel(); /* List of indexes of selected Rows */ private List<Integer> selectedRows = new ArrayList<>(); private FaceStatePanel faceStatePanel; private FilterPanel filterPanel; /** * Creates new form ProjectPanel */ public ProjectPanel() { project = new Project(); initComponents(); table.getColumnModel().getColumn(2).setCellEditor(new TaskCellEditor()); table.getColumnModel().getColumn(2).setCellRenderer(new TaskCellRenderer()); table.repaint(); } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; buttonsPanel = new javax.swing.JPanel(); addButton = new javax.swing.JButton(); removeButton = new javax.swing.JButton(); selectAllButton = new javax.swing.JButton(); deselectAllButton = new javax.swing.JButton(); inflateButton = new javax.swing.JButton(); analyseButton = new javax.swing.JButton(); saveProjectButton = new javax.swing.JButton(); openProjectButton = new javax.swing.JButton(); newProjectButton = new javax.swing.JButton(); tableScrollPane = new javax.swing.JScrollPane(); table = new javax.swing.JTable(); projectNameLabel = new javax.swing.JLabel(); projectNameOutput = new javax.swing.JLabel(); buttonsPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); buttonsPanel.setMinimumSize(new java.awt.Dimension(0, 0)); buttonsPanel.setLayout(new java.awt.GridBagLayout()); addButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(addButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.addButton.text")); // NOI18N addButton.setPreferredSize(new java.awt.Dimension(100, 30)); addButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { addButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 15); buttonsPanel.add(addButton, gridBagConstraints); removeButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(removeButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.removeButton.text")); // NOI18N removeButton.setPreferredSize(new java.awt.Dimension(100, 30)); removeButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 15); buttonsPanel.add(removeButton, gridBagConstraints); selectAllButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(selectAllButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.selectAllButton.text")); // NOI18N selectAllButton.setPreferredSize(new java.awt.Dimension(100, 30)); selectAllButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { selectAllButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 15); buttonsPanel.add(selectAllButton, gridBagConstraints); deselectAllButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(deselectAllButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.deselectAllButton.text")); // NOI18N deselectAllButton.setPreferredSize(new java.awt.Dimension(100, 30)); deselectAllButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deselectAllButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 15); buttonsPanel.add(deselectAllButton, gridBagConstraints); inflateButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(inflateButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.inflateButton.text")); // NOI18N inflateButton.setAlignmentX(0.5F); inflateButton.setPreferredSize(new java.awt.Dimension(100, 30)); inflateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { inflateButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(5, 15, 5, 15); buttonsPanel.add(inflateButton, gridBagConstraints); analyseButton.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(analyseButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.analyseButton.text")); // NOI18N analyseButton.setEnabled(false); analyseButton.setMaximumSize(new java.awt.Dimension(150, 23)); analyseButton.setMinimumSize(new java.awt.Dimension(150, 23)); analyseButton.setPreferredSize(new java.awt.Dimension(150, 30)); analyseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { analyseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new java.awt.Insets(5, 100, 5, 15); buttonsPanel.add(analyseButton, gridBagConstraints); saveProjectButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N saveProjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/save100x24.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(saveProjectButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.saveProjectButton.text")); // NOI18N saveProjectButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { saveProjectButtonActionPerformed(evt); } }); openProjectButton.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N openProjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open100x24.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(openProjectButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.openProjectButton.text")); // NOI18N openProjectButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { openProjectButtonActionPerformed(evt); } }); newProjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/new100x24.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newProjectButton, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.newProjectButton.text")); // NOI18N newProjectButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newProjectButtonActionPerformed(evt); } }); table.setSize(tableScrollPane.getWidth(), tableScrollPane.getHeight()); table.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N table.getTableHeader().setOpaque(false); table.getTableHeader().setBackground(new java.awt.Color(204,204,204)); table.getTableHeader().setFont(new java.awt.Font("Tahoma", 0, 18)); model.addTableModelListener(new TableModelListener() { public void tableChanged(TableModelEvent e) { jTable1TableChanged(e); } }); table.setModel(model); table.getColumnModel().getColumn(0).setMaxWidth(50); table.getColumnModel().getColumn(1).setPreferredWidth(400); table.getColumnModel().getColumn(2).setMaxWidth(250); table.getColumnModel().getColumn(2).setPreferredWidth(250); table.getColumnModel().getColumn(3).setMaxWidth(125); table.getColumnModel().getColumn(3).setPreferredWidth(125); table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50); table.getTableHeader().getColumnModel().getColumn(1).setPreferredWidth(400); table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(250); table.getTableHeader().getColumnModel().getColumn(2).setPreferredWidth(250); table.getTableHeader().getColumnModel().getColumn(3).setMaxWidth(125); table.getTableHeader().getColumnModel().getColumn(3).setPreferredWidth(125); table.setDragEnabled(true); table.setRowHeight(60); table.setSelectionBackground(new java.awt.Color(102, 204, 255)); table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); table.getTableHeader().setReorderingAllowed(false); table.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(java.awt.event.MouseEvent evt) { tableMouseClicked(evt); } }); tableScrollPane.setViewportView(table); projectNameLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(projectNameLabel, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.projectNameLabel.text")); // NOI18N projectNameOutput.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(projectNameOutput, org.openide.util.NbBundle.getMessage(ProjectPanel.class, "ProjectPanel.projectNameOutput.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(41, 41, 41) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(buttonsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 968, Short.MAX_VALUE) .addComponent(tableScrollPane)) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(newProjectButton) .addComponent(saveProjectButton) .addComponent(openProjectButton) .addGroup(layout.createSequentialGroup() .addComponent(projectNameLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(projectNameOutput, javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(buttonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addGap(29, 29, 29) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(projectNameOutput, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(projectNameLabel)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(newProjectButton) .addGap(19, 19, 19) .addComponent(saveProjectButton) .addGap(18, 18, 18) .addComponent(openProjectButton) .addGap(0, 0, Short.MAX_VALUE)) .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 768, Short.MAX_VALUE)) .addContainerGap(12, Short.MAX_VALUE)) ); }// </editor-fold>//GEN-END:initComponents public Project getProject() { return project; } public ModelsTableModel getModel() { return model; } public List<Integer> getSelectedRows() { return selectedRows; } public JTable getTable() { return table; } public void setSelectedRows(List<Integer> selectedRows) { this.selectedRows = selectedRows; } public void setFaceStatePanel(FaceStatePanel faceStatePanel) { this.faceStatePanel = faceStatePanel; } public void setFilterPanel(FilterPanel filterPanel) { this.filterPanel = filterPanel; } public boolean isProjectSaved() { return project.isSaved(); } private void tableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_tableMouseClicked if (table.getSelectedRowCount() == 0) { checkFaceState(null, false); } else { if (evt.getClickCount() == 2) { deselectAllRows(); // if cell is not editable, that means that row is being filtered // and new face tab analysis shouldn't be opened if (!model.isCellEditable(table.getSelectedRow(), 0)) { return; } model.setValueAt(true, table.getSelectedRow(), 0); analyseSingleFace(); } checkFaceState(table.getValueAt(table.getSelectedRow(), 1).toString(), true); } }//GEN-LAST:event_tableMouseClicked /** * Opens analysis of single selected face */ private void analyseSingleFace() { String name = model.getValueAt(selectedRows.get(0), 1).toString(); HumanFace face = project.loadFace(name); createSingleFaceTab(face, name, null); } /** * Opens analysis of two selected faces - 1:1 */ private void analyseOneOnOneFaces() { String name1 = model.getValueAt(selectedRows.get(0), 1).toString(); String name2 = model.getValueAt(selectedRows.get(1), 1).toString(); HumanFace face1 = project.loadFace(name1); HumanFace face2 = project.loadFace(name2); Object[] options = {face1.getShortName(), face2.getShortName()}; int choice = JOptionPane.showOptionDialog(this, "Faces: ", "Select primary face", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if (choice == 0) { createFaceToFaceTab(face1, face2, name1 + ":" + name2, null); } else { createFaceToFaceTab(face2, face1, name2 + ":" + name1, null); } } /** * Opens analysis of N:N selected faces */ private void analyseManyToManyFaces() { List<Path> faces = selectedRows.stream() .map(i -> model.getValueAt(i, 1).toString()) .map(s -> project.getCfg().getPathToFaceByName(s)) .collect(Collectors.toList()); createManyToManyTab(String.format("%s:N", String.valueOf(selectedRows.size())), faces); } private void analyseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_analyseButtonActionPerformed switch (selectedRows.size()) { case 0: JOptionPane.showMessageDialog(this, "None faces selected"); break; case 1: analyseSingleFace(); break; case 2: analyseOneOnOneFaces(); break; default: analyseManyToManyFaces(); break; } }//GEN-LAST:event_analyseButtonActionPerformed private void inflateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_inflateButtonActionPerformed model.inflateSelection(); }//GEN-LAST:event_inflateButtonActionPerformed private void deselectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deselectAllButtonActionPerformed deselectAllRows(); }//GEN-LAST:event_deselectAllButtonActionPerformed private void selectAllButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectAllButtonActionPerformed model.setAllRowsSelection(true); }//GEN-LAST:event_selectAllButtonActionPerformed private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed if (selectedRows.isEmpty()) { JOptionPane.showMessageDialog(this, "No face chosen"); return; } int answer = JOptionPane.showConfirmDialog(null, "Do you really want to remove all selected faces? Changes will be discarded", "", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (answer == JOptionPane.YES_OPTION) { removeSelectedFaces(); saveProject(); } }//GEN-LAST:event_removeButtonActionPerformed private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed loadModel(false); saveProject(); }//GEN-LAST:event_addButtonActionPerformed private void newProjectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newProjectButtonActionPerformed if (loadNewProject()) { newProject(); } }//GEN-LAST:event_newProjectButtonActionPerformed private void saveProjectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveProjectButtonActionPerformed if (saveNewProject(SAVE_CURRENT_PROJECT_TITLE)) { JOptionPane.showMessageDialog(this, "Project successfully saved!"); } }//GEN-LAST:event_saveProjectButtonActionPerformed private void openProjectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openProjectButtonActionPerformed if (loadNewProject()) { openProject(); } }//GEN-LAST:event_openProjectButtonActionPerformed /** * Removes selected faces (those which are checked in check boxes) */ private void removeSelectedFaces() { Collections.sort(selectedRows, Collections.reverseOrder()); selectedRows.forEach(row -> { String name = model.getValueAt(row, 1).toString(); List<FaceTab> tabsToClose = new ArrayList<>(); tabs.stream().filter(t -> (t.hasFace(name))).forEachOrdered(t -> { tabsToClose.add(t); }); while(!tabsToClose.isEmpty()) { // Remove tasks from other task if (tabsToClose.get(0).getFaces().isEmpty()) { model.removeTask(tabsToClose.get(0).getFace1().getShortName(), tabsToClose.get(0).getName()); if (tabsToClose.get(0).getFace2() != null) { model.removeTask(tabsToClose.get(0).getFace2().getShortName(), tabsToClose.get(0).getName()); } removeTaskFileFromProjectDir(tabsToClose.get(0)); } tabsToClose.get(0).close(); tabs.remove(tabsToClose.remove(0)); } // Remove already loaded and stored face info faceStatePanel.removeFaceByName(name); // Remove face from filter history if row is currently filtered if (row >= model.getRowCount() - filterPanel.getFilterHistory().getTotalFaces()) { filterPanel.getFilterHistory().removeFilteredFace(name); } model.removeRow(row); project.getCfg().removePath(name); }); selectedRows.clear(); } /** * Deselects all rows */ public void deselectAllRows() { model.setAllRowsSelection(false); } /** * Updates selectedRows - adds new selected rows or removes deselected rows * @param e TableModelEvent */ private void jTable1TableChanged(TableModelEvent e) { if (e.getType() == javax.swing.event.TableModelEvent.UPDATE) { int row = e.getFirstRow(); if (table.getValueAt(row, 0) == (Object)true) { if (!selectedRows.contains(row)) { selectedRows.add(row); } } else { if (selectedRows.contains(row)) { selectedRows.remove((Integer)row); } } // Disable when none faces are selected analyseButton.setEnabled(!selectedRows.isEmpty()); // Set text of analyse button switch (selectedRows.size()) { case 0: case 1: analyseButton.setText("Create Task"); break; case 2: analyseButton.setText("Create 1:1 Task"); break; default: analyseButton.setText(String.format("Create %d:N Task", selectedRows.size())); break; } } else if (e.getType() == javax.swing.event.TableModelEvent.INSERT || e.getType() == javax.swing.event.TableModelEvent.DELETE) { project.setSaved(false); } } /** * Loads model selected in file chooser by user * @param loadFromFile true if models are loaded from file, else user chooses * from FileChooserBuilder */ public void loadModel(boolean loadFromFile) { // Storing files with tasks which will be opened List<File> tasksToOpen = new ArrayList<>(); File[] files; // Selects files with faces (by dialog or from JSON file) if (!loadFromFile) { files = new FileChooserBuilder(ProjectTopComp.class) .setTitle("Open human face(s)") .setDefaultWorkingDirectory(new File(System.getProperty("user.home"))) //.setApproveText("Add") .setFileFilter(new FileNameExtensionFilter("obj files (*.obj)", "obj")) .setAcceptAllFileFilterUsed(true) .showMultiOpenDialog(); } else { files = new File[project.getCfg().getPaths().size()]; files = project.getCfg().openFiles().toArray(files); project.getCfg().clearPaths(); } if (files == null) { System.out.print("No file chosen."); } else { for (File file : files) { Path path = Paths.get(file.getAbsolutePath()); String name = path.toString().substring(path.toString() .lastIndexOf(File.separatorChar) + 1, path.toString().lastIndexOf('.')); tasksToOpen.addAll(loadFaceTasks(name)); if (project.addNewPath(path)) { ActionListener taskSelected = (ActionEvent e) -> { openTask(e); }; model.addRowWithName(name, path, taskSelected); } else { JOptionPane.showMessageDialog(this, String.format("Model %s is already loaded", name)); } } } loadTasks(tasksToOpen); } /** * Loads all tasks from files * @param tasksToOpen all files with tasks which should be opened */ private void loadTasks(List<File> tasksToOpen) { if (tasksToOpen.isEmpty()) { return; } ProgressDialog progressDialog = new ProgressDialog(this, "Loading tasks"); LoadTasksTask task = new LoadTasksTask(tasksToOpen, progressDialog); task.addPropertyChangeListener((PropertyChangeEvent evt) -> { if ("state".equals(evt.getPropertyName()) && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { List<Task> tasksRestored = task.getTasksRestored(); if (!tasksRestored.isEmpty()) { restoreTasks(tasksRestored); } } }); progressDialog.runTask(task); } /** * Restores data from tasks to tabs * @param tasksRestored tasks which should be restored to tabs */ private void restoreTasks(List<Task> tasksRestored) { tasksRestored.forEach(task -> { // Face to face analysis if (task.getSecondary() != null) { createFaceToFaceTab(task.getPrimary(), task.getSecondary(), task.getPrimary().getShortName() + ":" + task.getSecondary().getShortName(), task.getCamera()); // Single face analysis } else { createSingleFaceTab(task.getPrimary(), task.getPrimary().getShortName(), task.getCamera()); } }); } /** * Opens and requests active task from tasks * @param e ActionEvent */ private void openTask(ActionEvent e) { JComboBox comboBox = (JComboBox) e.getSource(); String taskName = String.valueOf(comboBox.getSelectedItem()); tabs.stream().filter(tab -> (tab.getName().equals(taskName))).forEachOrdered(tab -> { if (!tab.isOpened()) { tab.open(); } tab.requestActive(); }); } /** * Ends task * @param e ActionEvent */ public void endTask(ActionEvent e) { int answer = JOptionPane.showConfirmDialog(null, "Do you really want to end this task? Changes will be discarded", "", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (answer == JOptionPane.YES_OPTION) { FaceTab tab = (FaceTab)e.getSource(); if (tab.getFaces().isEmpty()) { // Remove task from face1 tasks model.removeTask(tab.getFace1().getShortName(), tab.getName()); if (tab.getFace2() != null) { // Remove task from face2 tasks model.removeTask(tab.getFace2().getShortName(), tab.getName()); } removeTaskFileFromProjectDir(tab); } tab.close(); tabs.remove(tab); } } /** * Removes task file from project directory - if project is saved * @param tab face tab with task which is about to be ended */ public void removeTaskFileFromProjectDir(FaceTab tab) { // If projects exists, try to delete task from project directory if (!project.getPathToProjectFile().isEmpty()) { String pathToProjectDir = project.getPathToProjectFile() .substring(0, project.getPathToProjectFile().lastIndexOf(File.separatorChar)); String name = tab.getFace1().getShortName(); if (tab.getFace2() != null) { name = tab.getFace1().getShortName() + "_TO_" + tab.getFace2().getShortName(); } String pathToTask = pathToProjectDir + File.separatorChar + name + ".bin"; Task.endTask(pathToTask); } } /** * Creates and opens tab with one face * @param face which will be analyzed * @param name name of the tab (name of the model) * @param camera camera or null */ public void createSingleFaceTab(HumanFace face, String name, Camera camera) { // Listener for ending task ActionListener endTaskListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { endTask(e); } }; FaceTab newTab = new FaceTab(face, null, name, endTaskListener, project); if (!tabs.contains(newTab)) { if (camera != null) { newTab.setCamera(camera); } model.addNewTask(name, name); tabs.add(newTab); newTab.open(); newTab.requestActive(); this.project.setSaved(false); } else { tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> { if (!t.isOpened()) { t.open(); } t.requestActive(); }); } } /** * Creates and opens tab with two faces (1:1 analysis) * @param face1 which will be analyzed * @param face2 which will be analyzed * @param nameOfTab name of the tab * @param camera camera or null */ public void createFaceToFaceTab(HumanFace face1, HumanFace face2, String nameOfTab, Camera camera) { // Listener for ending task ActionListener endTaskListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { endTask(e); } }; FaceTab newTab = new FaceTab(face1, face2, nameOfTab, endTaskListener, project); if (!tabs.contains(newTab)) { if (camera != null) { newTab.setCamera(camera); } model.addNewTask(face1.getShortName(), nameOfTab); model.addNewTask(face2.getShortName(), nameOfTab); tabs.add(newTab); newTab.open(); newTab.requestActive(); this.project.setSaved(false); } else { tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> { if (!t.isOpened()) { t.open(); } t.requestActive(); }); } } /** * Creates and opens tab with multiple faces for N:N analysis * @param faces faces to be analyzed * @param name name of the tab */ public void createManyToManyTab(String name, List<Path> faces) { // Listener for ending task ActionListener endTaskListener = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { endTask(e); } }; FaceTab newTab = new FaceTab(faces, name, endTaskListener); if (!tabs.contains(newTab)) { tabs.add(newTab); } newTab.open(); newTab.requestActive(); } /** * Opens info panel with face state information * @param faceName String name of face * @param selected Boolean true if some face is selected from list, false otherwise */ public void checkFaceState(String faceName, boolean selected) { Path path = project.getCfg().getPathToFaceByName(faceName); faceStatePanel.newSelection(selected, faceName, path); this.repaint(); } /** * Asks user whether he wants to create new empty project, or open existing * project */ public void openExistingOrNewProject() { File recentProjectFile = project.getRecentProject(); if (recentProjectFile != null) { openProjectFromFile(recentProjectFile); return; } ImageIcon newProjectImage = new ImageIcon(ProjectTopComp.class.getClassLoader().getResource("/" + "new.png")); ImageIcon existingProjectImage = new ImageIcon(ProjectTopComp.class.getClassLoader().getResource("/" + "open.png")); Object[] options = {newProjectImage, existingProjectImage}; int choice = JOptionPane.showOptionDialog(this, "Would you like to create a new project or open an existing project?", "Select project", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]); if (choice == 1) { openProject(); } else { saveNewProject(SAVE_NEW_PROJECT_TITLE); projectNameOutput.setText(project.getProjectName()); } } /** * Serializes all currently opened tasks */ public static void serializeTasks() { tabs.forEach(tab -> { try { tab.serializeTask(); } catch (IOException ex) { Exceptions.printStackTrace(ex); } }); } /** * Resets all project attributes */ public void closeProject() { if (!"".equals(this.project.getPathToProjectFile())) { serializeTasks(); } while (!tabs.isEmpty()) { tabs.get(0).close(); tabs.remove(0); } faceStatePanel.clearLoadedFaces(); filterPanel.clearFiltering(); model.setRowCount(0); checkFaceState(null, false); selectedRows.clear(); project.closeProject(); } /** * Checks whether current project is saved, if not then asks user if he wants * to save it * @return false if user cancels selection, true otherwise */ private boolean loadNewProject() { if (!project.isSaved()) { int showConfirmDialog = JOptionPane.showConfirmDialog(this, "Project is not saved. Would you like to save project?", "Save project", JOptionPane.YES_NO_CANCEL_OPTION); switch (showConfirmDialog) { case JOptionPane.YES_OPTION: saveNewProject(SAVE_CURRENT_PROJECT_TITLE); break; case JOptionPane.CANCEL_OPTION: case JOptionPane.CLOSED_OPTION: return false; default: break; } } return true; } /** * Tries to save current project - project might not be saved * @return true if project was saved successfully, false otherwise */ public boolean saveProject() { File file = null; // If current project was saved before String path = project.getPathToProjectFile(); if (path != null && !path.isEmpty()) { file = Paths.get(path).toFile(); } if (file != null) { project.saveProject(file); projectNameOutput.setText(project.getProjectName()); return true; } return false; } /** * Saves new project * @param title of chooser * @return true if project was saved successfully, false otherwise */ public boolean saveNewProject(String title) { if (saveProject()) { return true; } File file; JFileChooser chooser = new JFileChooser(); //chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); //chooser.setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json")); chooser.setAcceptAllFileFilterUsed(true); chooser.setDialogTitle(title); chooser.showSaveDialog(null); file = chooser.getSelectedFile(); if (file != null) { // Create new project folder file.mkdir(); String pathToFolder = file.getAbsolutePath(); String pathToProject = pathToFolder.concat(File.separatorChar + chooser.getName(file) + ".json"); // Create project file inside the project folder file = new File(pathToProject); return project.saveProject(file); } return false; } /** * Opens project from file * @param f File */ private void openProjectFromFile(File f) { if (f != null) { closeProject(); if (!project.openProjectFromFile(f)) { JOptionPane.showMessageDialog(this, "Couldn't load project", "Loading project failed", JOptionPane.ERROR_MESSAGE); } loadModel(true); projectNameOutput.setText(project.getProjectName()); } } /** * Opens project, which user selects in File Chooser */ private void openProject() { File f; f = new FileChooserBuilder(ProjectTopComp.class) .setTitle("Choose existing project") .setDefaultWorkingDirectory(new File(System.getProperty("user.home"))) .setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json")) .setAcceptAllFileFilterUsed(true) .showOpenDialog(); openProjectFromFile(f); } /** * Creates new project */ private void newProject() { closeProject(); project.newProject(); saveNewProject(SAVE_NEW_PROJECT_TITLE); projectNameOutput.setText(project.getProjectName()); } /** * Loads currently selected (clicked in table) face geometry info */ public void loadCurrentlySelectedFace() { if (table.getSelectedRow() == -1) { JOptionPane.showMessageDialog(faceStatePanel, "None model selected", "Select model", JOptionPane.WARNING_MESSAGE); return; } String name = table.getValueAt(table.getSelectedRow(), 1).toString(); HumanFace face = project.loadFace(name); faceStatePanel.loadFaceGeometryInfo(face); checkFaceState(name, true); } /** * Gets files where face is primary face * @param faceName name of the face * @return Files with serialized tasks where face is primary face */ public List<File> loadFaceTasks(String faceName) { if ("".equals(project.getPathToProjectFile())) { return Collections.EMPTY_LIST; } Path pathToProjectFolder = Paths.get(project.getPathToProjectFile() .substring(0, project.getPathToProjectFile().lastIndexOf(File.separatorChar))); File dir = new File(pathToProjectFolder.toString()); File[] files = dir.listFiles((File dir1, String name1) -> name1.startsWith(faceName)); return Arrays.asList(files); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addButton; private javax.swing.JButton analyseButton; private javax.swing.JPanel buttonsPanel; private javax.swing.JButton deselectAllButton; private javax.swing.JButton inflateButton; private javax.swing.JButton newProjectButton; private javax.swing.JButton openProjectButton; private javax.swing.JLabel projectNameLabel; private javax.swing.JLabel projectNameOutput; private javax.swing.JButton removeButton; private javax.swing.JButton saveProjectButton; private javax.swing.JButton selectAllButton; private javax.swing.JTable table; private javax.swing.JScrollPane tableScrollPane; // End of variables declaration//GEN-END:variables }