Skip to content
Snippets Groups Projects
ProjectPanel.java 37.9 KiB
Newer Older
package cz.fidentis.analyst.project;
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 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.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(new Object[]{"", "Models", "Preview"}, 0);

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();
        faceTableScrollPanel = new javax.swing.JScrollPane();
        table = new javax.swing.JTable();
        saveProjectButton = new javax.swing.JButton();
        openProjectButton = new javax.swing.JButton();
        newProjectButton = new javax.swing.JButton();
        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.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.ipadx = 20;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(16, 0, 13, 4);
        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.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.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(16, 22, 13, 4);
        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.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.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(16, 22, 13, 4);
        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.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.NORTHWEST;
        gridBagConstraints.insets = new java.awt.Insets(16, 22, 13, 4);
        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.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.NORTHWEST;
Matej Kovár's avatar
Matej Kovár committed
        gridBagConstraints.insets = new java.awt.Insets(16, 22, 13, 4);
        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.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(16, 75, 13, 4);
        buttonsPanel.add(analyseButton, gridBagConstraints);
        faceTableScrollPanel.setPreferredSize(new java.awt.Dimension(812, 750));
        table.setSize(faceTableScrollPanel.getWidth(), faceTableScrollPanel.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);
Matej Kovár's avatar
Matej Kovár committed
        table.getColumnModel().getColumn(2).setMaxWidth(85);
        table.getTableHeader().getColumnModel().getColumn(0).setMaxWidth(50);
        table.getTableHeader().getColumnModel().getColumn(2).setMaxWidth(75);
        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) {
        faceTableScrollPanel.setViewportView(table);
        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);
            }
        });

        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.TRAILING)
                    .addComponent(saveProjectButton)
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(faceTableScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 863, Short.MAX_VALUE)
                            .addComponent(buttonsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(layout.createSequentialGroup()
                                .addGap(78, 78, 78)
                                .addComponent(newProjectButton))
                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(openProjectButton)))))
                .addContainerGap(41, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(23, 23, 23)
                        .addComponent(newProjectButton))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(buttonsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(faceTableScrollPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 768, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(saveProjectButton)
                        .addGap(18, 18, 18)
                        .addComponent(openProjectButton)))
                .addContainerGap(12, Short.MAX_VALUE))
    }// </editor-fold>//GEN-END:initComponents

    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();
                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);
        if (project.getFaceByName(name) == null) {    
            project.addFace(face);
        }
        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);

        if (project.getFaceByName(name1) == null) {
            project.addFace(face1);
        }

        if (project.getFaceByName(name2) == null) {
            project.addFace(face2);
        
        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
Matej Kovár's avatar
Matej Kovár committed
        for (int i = 0; i < model.getRowCount(); i++) {
            if (model.getValueAt(i, 0) == (Object) true) {
                model.setValueAt(false, i, 0);
            } else {
                model.setValueAt(true, i, 0);
            }
Matej Kovár's avatar
Matej Kovár committed
        }
    }//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
        for (int i = 0; i < model.getRowCount(); i++) {
            model.setValueAt(true, i, 0);
    }//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();
            }
            
            project.removeFaceByName(name);
        selectedRows.clear();  
     * Deselects all rows
     * TODO : deselect only rows which are selected (checking row by row is slow)
    private void deselectAllRows() {
        for (int i = 0; i < model.getRowCount(); i++) {
            model.setValueAt(false, i, 0);
    
    /**
     * 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);
Matej Kovár's avatar
Matej Kovár committed

    /**
     * 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)) {  
Matej Kovár's avatar
Matej Kovár committed
                    //Path preview = path.resolveSibling(name.concat("_preview_small.jpg"));
                    Path preview = path.resolveSibling(name.concat("_preview.jpg"));
                    model.addRowWithName(name, preview);
                    filterPanel.checkAllFacesLoaded(false);

                    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);
                    }
                });
            }
    
    /**
     * Checks whether face is already loaded in some tab and if it is different tab
     * (different tabName) than opens this face again from file (copy of face)
     * @param tabName String name of tab which is about to be opened
     * @param face HumanFace which will be in tab
     * @return either loaded face from project or newly opened face from file
     */
    private HumanFace getLoadedOrNewFace(String tabName, HumanFace face) {
        for (FaceTab t : tabs) {
            
            if (t.hasFace(face.getShortName()) && !t.getName().equals(tabName)) {
                
                try {
                    return new HumanFace(Paths.get(face.getPath()).toFile(), true);
                   
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        }
        return face;
    }
    
    /**
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);
            }
        // Check if face is already loaded in some other tab - if not, face 
        // is not open from path but loaded from project
        face = getLoadedOrNewFace(name, face);
        FaceTab newTab = new FaceTab(face, null, name, tabCloseListener);
        if (!tabs.contains(newTab)) {
            tabs.add(newTab);
            if (!loadFromFile) {
                project.addNewSingleFaceTabFace(name);
            }
            newTab.open();
            newTab.requestActive();
            this.project.setSaved(false);    
            areAllFacesLoadedToProject();
            
        } 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);
            }
        };
        
        // Check if face is already loaded in some other tab - if not, face 
        // is not open from path but loaded from project
        face1 = getLoadedOrNewFace(nameOfTab, face1);
        face2 = getLoadedOrNewFace(nameOfTab, face2);
        FaceTab newTab = new FaceTab(face1, face2, nameOfTab, tabCloseListener);
        
        if (!tabs.contains(newTab)) {

            tabs.add(newTab);
            if (!loadFromFile) {
                project.addNewFaceToFaceTabFace(face1.getShortName(), face2.getShortName());
            }
            newTab.open();
            newTab.requestActive();
            this.project.setSaved(false);
            areAllFacesLoadedToProject();
        } 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
    private void checkFaceState(String faceName, boolean selected) {
    
        HumanFace face = project.getFaceByName(faceName);
        Path path = project.getCfg().getPathToFaceByName(faceName);
        faceStatePanel.newSelection(selected, face, faceName, path);
    /**
     * Sorts faces by alphabet
     */
    private void alphabeticalFilter() {
        this.deselectAllRows();
        /*
        TableRowSorter<TableModel> sorter = new TableRowSorter<>(model);
        jTable1.setRowSorter(sorter);
        
        List<RowSorter.SortKey> sortKeys = new ArrayList<>();
        sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING));
        sorter.setSortKeys(sortKeys);*/
        
        List<String> names = new ArrayList();
        while (model.getRowCount() > 0) {
            names.add(model.getValueAt(0, 1).toString());
            model.removeRow(0);
        }
        Collections.sort(names);
        names.forEach(name -> {
            HumanFace face = project.getFaceByName(name);
            String pathString = face.getPath();
            Path preview = Paths.get(pathString.substring(0, pathString.lastIndexOf(".")).concat("_preview.jpg"));
            model.addRowWithName(name, preview);
        });
        
    }
    
    /**
     * Removes faces from project (and table of faces) based on filter configuration
     */
    public void applyFilter(boolean isFeaturePointsFilter, boolean isKdTreeFilter, boolean isAlphaBeticalFilter) {
        for (int i = 0; i < model.getRowCount(); i++) { 
            HumanFace face = project.getFaceByName(model.getValueAt(i, 1).toString());
            
            if ((isKdTreeFilter && !face.hasKdTree()) || (isFeaturePointsFilter && !face.hasFeaturePoints())) {
        if (isAlphaBeticalFilter) {
    /**
     * 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();
        }
        project.removeAll();
        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 
     */
    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 to project
     */
    public void loadCurrentlySelectedFace() {
        String name = table.getValueAt(table.getSelectedRow(), 1).toString();
        project.loadFace(name);
        checkFaceState(name, true);
        areAllFacesLoadedToProject();
    }
    
    /**
     * Checks whether all faces from list are loaded to project
     */
    public void areAllFacesLoadedToProject() {
        
        for (int i = 0; i < model.getRowCount(); i++) {
            HumanFace face = project.getFaceByName(model.getValueAt(i, 1).toString());
            
            if (face == null) {
                filterPanel.checkAllFacesLoaded(false);
        filterPanel.checkAllFacesLoaded(true);

     * Loads all faces from list to project
     */
    public void loadAllFaces() {
        
        for (int i = 0; i < model.getRowCount(); i++) {
            
            String name = model.getValueAt(i, 1).toString();
            project.loadFace(name);
        filterPanel.checkAllFacesLoaded(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.JScrollPane faceTableScrollPanel;
    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;
    // End of variables declaration//GEN-END:variables