Skip to content
Snippets Groups Projects
ProjectPanel.java 34.7 KiB
Newer Older
package cz.fidentis.analyst.project;
import cz.fidentis.analyst.faceState.FaceStatePanel;
import com.fasterxml.jackson.databind.ObjectMapper;
Matej Kovár's avatar
Matej Kovár committed
import cz.fidentis.analyst.Project;
import cz.fidentis.analyst.ProjectConfiguration;
import cz.fidentis.analyst.core.FaceTab;
import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.filter.FilterPanel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
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.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JTable;
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 {
    
    private Project project;
    private 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 ObjectMapper mapper = new ObjectMapper();
    
    private Preferences userPreferences = Preferences.userNodeForPackage(Project.class); 
    
    private FaceStatePanel faceStatePanel;
    private FilterPanel filterPanel;
     * Creates new form ProjectPanel
    public ProjectPanel() {
        project = new Project();
        initComponents();
    }

    /**
     * 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();
        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.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                addButtonMouseClicked(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.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                removeButtonMouseClicked(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.addMouseListener(new java.awt.event.MouseAdapter() {
Matej Kovár's avatar
Matej Kovár committed
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                selectAllButtonMouseClicked(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.addMouseListener(new java.awt.event.MouseAdapter() {
Matej Kovár's avatar
Matej Kovár committed
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                deselectAllButtonMouseClicked(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.addMouseListener(new java.awt.event.MouseAdapter() {
Matej Kovár's avatar
Matej Kovár committed
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                inflateButtonMouseClicked(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.setPreferredSize(new java.awt.Dimension(100, 30));
        analyseButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent 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.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                saveProjectButtonMouseClicked(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.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                openProjectButtonMouseClicked(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.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                newProjectButtonMouseClicked(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(2).setMaxWidth(75);
        table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50);
        table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(85);
        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);
        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, 1025, Short.MAX_VALUE)
                    .addComponent(tableScrollPane))
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                            .addGap(50, 50, 50)
                            .addComponent(newProjectButton))
                        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                            .addComponent(saveProjectButton)))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(openProjectButton)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(buttonsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 768, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(61, 61, 61)
                        .addComponent(newProjectButton)
                        .addGap(18, 18, 18)
                        .addComponent(saveProjectButton)
                        .addGap(18, 18, 18)
                        .addComponent(openProjectButton)
                        .addGap(0, 0, 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 newProjectButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_newProjectButtonMouseClicked
        if (loadNewProject()) {
            newProject();
        }
    }//GEN-LAST:event_newProjectButtonMouseClicked

    private void openProjectButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_openProjectButtonMouseClicked
        if (loadNewProject()) {
            openProject();
        }
    }//GEN-LAST:event_openProjectButtonMouseClicked

    private void saveProjectButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_saveProjectButtonMouseClicked
        saveProject();
    }//GEN-LAST:event_saveProjectButtonMouseClicked

    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, false);
    }
    
    /**
     * 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, false);
        } else {
            createFaceToFaceTab(face2, face1, name2 + ":" + name1, false);
        }
        
    }
    
    /**
     * 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());
        
    private void inflateButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_inflateButtonMouseClicked
        model.inflateSelection();
    }//GEN-LAST:event_inflateButtonMouseClicked
    private void deselectAllButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_deselectAllButtonMouseClicked
    }//GEN-LAST:event_deselectAllButtonMouseClicked
    private void selectAllButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_selectAllButtonMouseClicked
        model.setAllRowsSelection(true);
    }//GEN-LAST:event_selectAllButtonMouseClicked
    private void removeButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_removeButtonMouseClicked
    }//GEN-LAST:event_removeButtonMouseClicked

    private void addButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_addButtonMouseClicked
        loadModel(false);
    }//GEN-LAST:event_addButtonMouseClicked

    private void analyseFaces(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_analyseFaces
        
        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_analyseFaces
     * 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()) {
                tabsToClose.remove(0).close();
            }
            // 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);
                }   
            }
        } 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) {
        File[] files;
        
        // 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('.'));
                if (project.addNewPath(path)) {  
                    model.addRowWithName(name, path);
                    JOptionPane.showMessageDialog(this, 
                            String.format("Model %s is already loaded", 
                            name));
Matej Kovár's avatar
Matej Kovár committed
        }
    
    /**
     * Loads tabs from project file
     */
    private void loadTabs() {
        
        project.getCfg().getSingleTabFaces().forEach(name -> {
            HumanFace face1 = project.loadFace(name);
            if (face1 != null) {
                createSingleFaceTab(face1, name, true);
            }
        project.getCfg().getFaceToFaceTabFaces().keySet().forEach(name -> {
            HumanFace face1 = project.loadFace(name);
            if (face1 != null) {
                project.getCfg().getFaceToFaceTabFaces().get(name).forEach(otherName -> {
                    HumanFace face2 = project.loadFace(otherName);
                    if (face2 != null) {
                        createFaceToFaceTab(face1, face2, name + ":" + otherName, true);
                    }
                });
            }
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)
    */
    private void createSingleFaceTab(HumanFace face, String name, boolean loadFromFile) {
        ActionListener tabCloseListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                closeTab(e);
            }
        FaceTab newTab = new FaceTab(face, null, name, tabCloseListener, project);
        if (!tabs.contains(newTab)) {
            tabs.add(newTab);
            if (!loadFromFile) {
                project.addNewSingleFaceTabFace(name);
            }
            newTab.open();
            newTab.requestActive();
            this.project.setSaved(false);    
            
        } else {
            
            tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> {
                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 name name of the tab
     */
    private void createFaceToFaceTab(HumanFace face1, HumanFace face2, String nameOfTab, boolean loadFromFile) {
        ActionListener tabCloseListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                closeTab(e);
            }
        };
        
        FaceTab newTab = new FaceTab(face1, face2, nameOfTab, tabCloseListener, project);
        
        if (!tabs.contains(newTab)) {

            tabs.add(newTab);
            if (!loadFromFile) {
                project.addNewFaceToFaceTabFace(face1.getShortName(), face2.getShortName());
            }
            newTab.open();
            newTab.requestActive();
            this.project.setSaved(false);
        } else {
            tabs.stream().filter(t -> (t.equals(newTab))).forEachOrdered(t -> {
                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
     */
    private void createManyToManyTab(String name, List<Path> faces) {
        ActionListener tabCloseListener = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                closeTab(e);
            }
        };
        FaceTab newTab = new FaceTab(faces, name, tabCloseListener);
        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 = 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();      
        }
    }
    
    /**
     * Resets all project attributes
     */
    private void resetProject() {
        
        while (!tabs.isEmpty()) {
            tabs.get(0).close();
        }
        faceStatePanel.clearLoadedFaces();
        filterPanel.clearFiltering();
        model.setRowCount(0);
        checkFaceState(null, false);
        selectedRows.clear();        
Matej Kovár's avatar
Matej Kovár committed
        userPreferences.remove("pathToMostRecentProject");
    }
    
    /**
     * 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:
                    saveProject();
                    break;
                case JOptionPane.CANCEL_OPTION:
                case JOptionPane.CLOSED_OPTION:
                    return false;
                default:
                    break;
            }
        }
        return true;
    }
    
    /**
     * Saves current project
     */
    public void saveProject() {
Matej Kovár's avatar
Matej Kovár committed
        File file;
Matej Kovár's avatar
Matej Kovár committed
        // If current project was saved before
        String path = userPreferences.get("pathToMostRecentProject", "");
        if (path != null && !path.isEmpty()) {
            file = Paths.get(path).toFile();
            
        // Project was not saved before, user chooses new path where to save project
        } else {
            JFileChooser chooser = new JFileChooser();
            //chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            chooser.setFileFilter(new FileNameExtensionFilter("json files (*.json)", "json"));
            chooser.setAcceptAllFileFilterUsed(true);
            chooser.showSaveDialog(null);

            file = chooser.getSelectedFile();
        }
        
        if (file != null) {
            String filePath = file.getAbsolutePath();
            if (!filePath.endsWith(".json")) {
                file = new File(filePath.concat(".json"));
            }

            try {
                mapper.writeValue(file, project.getCfg());
                userPreferences.put("pathToMostRecentProject", file.getAbsolutePath());
                project.setSaved(true);
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }
        }
   
    }
    private void openProjectFromFile(File f) {
        
        if (f != null) {
            try {
                resetProject();
                project.setCfg(mapper.readValue(f, ProjectConfiguration.class));
                loadModel(true);    
                userPreferences.put("pathToMostRecentProject", f.getAbsolutePath());
                project.setSaved(true);
            } catch (IOException ex) {
                //Exceptions.printStackTrace(ex);
                JOptionPane.showMessageDialog(this, 
                        "Couldn't load project", 
                        "Loading project failed", 
                        JOptionPane.ERROR_MESSAGE);
        } 
    }
    
    /**
     * Loads most recent project from user preferences
     * @return File where project is saved, null if no project was found
     */
    public File getRecentProject() {
        
        String path = userPreferences.get("pathToMostRecentProject", "");
        if (path.equals("")) {
            return null;
        }
        Path f = Paths.get(path);
        return f.toFile();
    }
    
    /**
     * 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() {    
        resetProject();
        project.setCfg(new ProjectConfiguration());
        project.setSaved(true);
    }

    /**
     * Closes tab
     * @param e ActionEvent
     */
    private void closeTab(ActionEvent e) {
        FaceTab tab = (FaceTab)e.getSource();
        
        for (FaceTab t : tabs) {
            if (t.equals(tab)) {
                          
                if (e.getActionCommand().equals("FaceTab")) {
                    this.project.removeFaceTab(t.getNameOfFace1());
                } else if (e.getActionCommand().equals("FaceToFaceTab")){
                    this.project.removeFaceToFaceTab(t.getNameOfFace1(), t.getNameOfFace2());
                }
                tabs.remove(t);
                break;
            }
        }
        
        //this.requestActive();
     * 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);
        
    // 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.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