Skip to content
Snippets Groups Projects
ProjectPanel.java 43.3 KiB
Newer Older
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;
Radek Ošlejšek's avatar
Radek Ošlejšek committed
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.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;
Matej Kovár's avatar
Matej Kovár committed
 *
 * @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();
Matej Kovár's avatar
Matej Kovár committed
    /* List of indexes of selected Rows */
    private List<Integer> selectedRows = new ArrayList<>();
Matej Kovár's avatar
Matej Kovár committed
    
    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() {
Matej Kovár's avatar
Matej Kovár committed
        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);
Matej Kovár's avatar
Matej Kovár committed
        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);
Matej Kovár's avatar
Matej Kovár committed

        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);
Matej Kovár's avatar
Matej Kovár committed
        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);
Matej Kovár's avatar
Matej Kovár committed

        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);
Matej Kovár's avatar
Matej Kovár committed
        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);
Matej Kovár's avatar
Matej Kovár committed

        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);
Matej Kovár's avatar
Matej Kovár committed
        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);
Matej Kovár's avatar
Matej Kovár committed

        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);
Matej Kovár's avatar
Matej Kovár committed
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 4;
Matej Kovár's avatar
Matej Kovár committed
        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.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) {
        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.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) {
        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))
                .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)
                        .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);
            }
            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]);
            createFaceToFaceTab(face1, face2, name1 + ":" + name2, null);
            createFaceToFaceTab(face2, face1, name2 + ":" + name1, null);
    }
    
    /**
     * Opens analysis of N:N selected faces
     */
    private void analyseManyToManyFaces() {
        
        List<Path> faces = selectedRows.stream()
Matej Kovár's avatar
Matej Kovár committed
                .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);
            }
            
            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<>();
        
        // Selects files with faces (by dialog or from JSON file)
        if (!loadFromFile) {
            files = new FileChooserBuilder(ProjectTopComp.class)
                .setTitle("Open human face(s)")
Matej Kovár's avatar
Matej Kovár committed
                .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();
        }
            System.out.print("No file chosen.");
        } else {
                
                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);
                    JOptionPane.showMessageDialog(this, 
                            String.format("Model %s is already loaded", 
                            name));
Matej Kovár's avatar
Matej Kovár committed
        }
     * 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);

        }
    }
    
Matej Kovár's avatar
Matej Kovár committed
    * 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
Matej Kovár's avatar
Matej Kovár committed
    */
    public void createSingleFaceTab(HumanFace face, String name, Camera camera) {
        // Listener for ending task
        ActionListener endTaskListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent 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();
            });
Matej Kovár's avatar
Matej Kovár committed
    /**
     * 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
Matej Kovár's avatar
Matej Kovár committed
     */
    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) {
        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);
            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) {
        
        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();
            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();
        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;

Matej Kovár's avatar
Matej Kovár committed
        // If current project was saved before
        String path = project.getPathToProjectFile();
        
Matej Kovár's avatar
Matej Kovár committed
        if (path != null && !path.isEmpty()) {
            file = Paths.get(path).toFile();
        }
            project.saveProject(file);
            projectNameOutput.setText(project.getProjectName());
            return true;
        }
        return false;
    }
    
    /**
     * Saves new project