<commit_before>package elegit.treefx;

import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;

import java.util.ArrayList;
import java.util.List;

/**
 * Handles the layout of cells in a TreeGraph in an appropriate tree structure
 */
public class TreeLayout{

    public static int V_SPACING = Cell.BOX_SIZE + 10;
    public static int H_SPACING = Cell.BOX_SIZE * 3 + 5;
    public static int V_PAD = 10;
    public static int H_PAD = 25;


    /**
     * Mover service to go through moving the cells. Services are scheduled really well, so we
     * like using them for big repetitive things like this.
     */
    public static class MoveCellService extends Service {
        private int currentCell, percent, max;
        private List<Cell> allCellsSortedByTime;

        public MoveCellService (List<Cell> allCellsSortedByTime) {
            this.allCellsSortedByTime = allCellsSortedByTime;
            this.max = allCellsSortedByTime.size()-1;
            this.percent = 0;
            this.currentCell = 0;
        }

        public void setCurrentCell(int currentCell) { this.currentCell = currentCell; }

        protected synchronized Task createTask() {
            return new Task() {
                @Override
                protected Object call() throws Exception {
                    moveCell(allCellsSortedByTime.get(currentCell));

                    // Update progress if need be
                    if (100-(max*100.0/currentCell%100)>percent) {
                        updateProgress(currentCell, max);
                        percent++;
                    }
                    return null;
                }
            };
        }
    }

    /**
     * Returns a task that will take care of laying out the given
     * graph into a tree. Uses a combination of recursion and
     * iteration to pack cells as far up as possible with each
     * cell being arranged horizontally based on time
     * @param g the graph to layout
     * @return a task that, when executed, does the layout of g
     */
    public static Task getTreeLayoutTask(TreeGraph g){

        return new Task<Void>(){

            private List<Cell> allCellsSortedByTime;
            private List<Integer> maxColUsedInRow;
            private List<Integer> movedCells;
            private boolean isInitialSetupFinished;

            /**
             * Extracts the TreeGraphModel, sorts its cells by time, then relocates
             * every cell. When complete, updates the model if necessary to show
             * it has been through the layout process at least once already
             */
            @Override
            protected Void call() throws Exception{
                TreeGraphModel treeGraphModel = g.treeGraphModel;
                isInitialSetupFinished = treeGraphModel.isInitialSetupFinished;

                allCellsSortedByTime = treeGraphModel.allCells;
                sortListOfCells();

                maxColUsedInRow = new ArrayList<>();
                movedCells = new ArrayList<>();


                // Compute the positions of cells recursively
                for (int i=allCellsSortedByTime.size()-1; i>=0; i--) {
                    computeCellPosition(i);
                }

                MoveCellService mover = new MoveCellService(allCellsSortedByTime);
                mover.setOnSucceeded(event1 -> {
                    mover.setCurrentCell(mover.currentCell+1);
                    mover.restart();
                });
                mover.setOnCancelled(event1 -> {
                    treeGraphModel.isInitialSetupFinished = true;
                });
                mover.start();

                return null;
            }


            /**
             * Helper method to sort the list of cells
             */
            private void sortListOfCells() {
                allCellsSortedByTime.sort((c1, c2) -> {
                    int i = Long.compare(c2.getTime(), c1.getTime());
                    if(i == 0){
                        if(c2.getCellChildren().contains(c1)){
                            return -1;
                        }else if(c1.getCellChildren().contains(c2)){
                            return 1;
                        }
                    }
                    return i;
                });
            }


            /**
             * Helper method that computes the cell position for a given cell and its parents (oldest to newest), recursively
             * @param cellPosition position of cell to compute position for
             */
            public void computeCellPosition(int cellPosition) {
                // Don't try to compute a new position if the cell has already been moved
                if (movedCells.contains(cellPosition))
                    return;

                // Get cell at rightmost location not yet placed
                Cell c = allCellsSortedByTime.get(allCellsSortedByTime.size()-1-cellPosition);

                setCellPosition(c, cellPosition, getRowOfCellInColumn(maxColUsedInRow, cellPosition));

                // Update the reserved columns in rows with the cells parents, oldest to newest
                List<Cell> list = c.getCellParents();
                list.sort((c1, c2) -> Long.compare(c1.getTime(), c2.getTime()));

                // For each parent, oldest to newest, place it in the highest row possible recursively
                for(Cell parent : list){
                    computeCellPosition(allCellsSortedByTime.indexOf(parent));
                }
            }

            public void setCellPosition(Cell c, int x, int y) {
                // See whether or not this cell will move
                int oldColumnLocation = c.columnLocationProperty.get();
                int oldRowLocation = c.rowLocationProperty.get();
                c.columnLocationProperty.set(x);
                c.rowLocationProperty.set(y);

                boolean hasCellMoved = oldColumnLocation >= 0 && oldRowLocation >= 0;
                boolean willCellMove = oldColumnLocation != x || oldRowLocation != y;

                // Update where the cell has been placed
                if (y >= maxColUsedInRow.size())
                    maxColUsedInRow.add(x);
                else
                    maxColUsedInRow.set(y, x);

                // Set the animation and use parent properties of the cell
                c.setAnimate(isInitialSetupFinished && willCellMove);
                c.setUseParentAsSource(!hasCellMoved);<commit_msg>Layout algorithm is working along with move cell. Now just have to include the progress bar stuff from fast_startup branch<commit_after>package elegit.treefx;

import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;

import java.util.ArrayList;
import java.util.List;

/**
 * Handles the layout of cells in a TreeGraph in an appropriate tree structure
 */
public class TreeLayout{

    public static int V_SPACING = Cell.BOX_SIZE + 10;
    public static int H_SPACING = Cell.BOX_SIZE * 3 + 5;
    public static int V_PAD = 10;
    public static int H_PAD = 25;


    /**
     * Mover service to go through moving the cells. Services are scheduled really well, so we
     * like using them for big repetitive things like this.
     */
    public static class MoveCellService extends Service {
        private int currentCell, percent, max;
        private List<Cell> allCellsSortedByTime;

        public MoveCellService (List<Cell> allCellsSortedByTime) {
            this.allCellsSortedByTime = allCellsSortedByTime;
            this.max = allCellsSortedByTime.size()-1;
            this.percent = 0;
            this.currentCell = 0;
        }

        public void setCurrentCell(int currentCell) { this.currentCell = currentCell; }

        protected synchronized Task createTask() {
            return new Task() {
                @Override
                protected Object call() throws Exception {
                    moveCell(allCellsSortedByTime.get(currentCell));

                    // Update progress if need be
                    if (100-(max*100.0/currentCell%100)>percent) {
                        updateProgress(currentCell, max);
                        percent++;
                    }
                    return null;
                }
            };
        }
    }

    /**
     * Returns a task that will take care of laying out the given
     * graph into a tree. Uses a combination of recursion and
     * iteration to pack cells as far up as possible with each
     * cell being arranged horizontally based on time
     * @param g the graph to layout
     * @return a task that, when executed, does the layout of g
     */
    public static Task getTreeLayoutTask(TreeGraph g){

        return new Task<Void>(){

            private List<Cell> allCellsSortedByTime;
            private List<Integer> maxColUsedInRow;
            private List<Integer> movedCells;
            private boolean isInitialSetupFinished;

            /**
             * Extracts the TreeGraphModel, sorts its cells by time, then relocates
             * every cell. When complete, updates the model if necessary to show
             * it has been through the layout process at least once already
             */
            @Override
            protected Void call() throws Exception{
                TreeGraphModel treeGraphModel = g.treeGraphModel;
                isInitialSetupFinished = treeGraphModel.isInitialSetupFinished;

                allCellsSortedByTime = treeGraphModel.allCells;
                sortListOfCells();

                maxColUsedInRow = new ArrayList<>();
                movedCells = new ArrayList<>();


                // Compute the positions of cells recursively
                for (int i=allCellsSortedByTime.size()-1; i>=0; i--) {
                    computeCellPosition(i);
                }

                MoveCellService mover = new MoveCellService(allCellsSortedByTime);
                mover.setOnSucceeded(event1 -> {
                    mover.setCurrentCell(mover.currentCell+1);
                    mover.restart();
                });
                mover.setOnCancelled(event1 -> {
                    treeGraphModel.isInitialSetupFinished = true;
                });
                mover.start();

                return null;
            }


            /**
             * Helper method to sort the list of cells
             */
            private void sortListOfCells() {
                allCellsSortedByTime.sort((c1, c2) -> {
                    int i = Long.compare(c2.getTime(), c1.getTime());
                    if(i == 0){
                        if(c2.getCellChildren().contains(c1)){
                            return -1;
                        }else if(c1.getCellChildren().contains(c2)){
                            return 1;
                        }
                    }
                    return i;
                });
            }


            /**
             * Helper method that computes the cell position for a given cell and its parents (oldest to newest), recursively
             * @param cellPosition position of cell to compute position for
             */
            public void computeCellPosition(int cellPosition) {
                // Don't try to compute a new position if the cell has already been moved
                if (movedCells.contains(cellPosition))
                    return;

                // Get cell at rightmost location not yet placed
                Cell c = allCellsSortedByTime.get(allCellsSortedByTime.size()-1-cellPosition);

                setCellPosition(c, cellPosition, getRowOfCellInColumn(maxColUsedInRow, cellPosition));

                // Update the reserved columns in rows with the cells parents, oldest to newest
                List<Cell> list = c.getCellParents();
                list.sort((c1, c2) -> Long.compare(c1.getTime(), c2.getTime()));

                // For each parent, oldest to newest, place it in the highest row possible recursively
                for(Cell parent : list){
                    computeCellPosition(allCellsSortedByTime.size()-1-allCellsSortedByTime.indexOf(parent));
                    break;
                }
            }

            public void setCellPosition(Cell c, int x, int y) {
                // See whether or not this cell will move
                int oldColumnLocation = c.columnLocationProperty.get();
                int oldRowLocation = c.rowLocationProperty.get();
                c.columnLocationProperty.set(x);
                c.rowLocationProperty.set(y);

                boolean hasCellMoved = oldColumnLocation >= 0 && oldRowLocation >= 0;
                boolean willCellMove = oldColumnLocation != x || oldRowLocation != y;

                // Update where the cell has been placed
                if (y >= maxColUsedInRow.size())
                    maxColUsedInRow.add(x);
                else
                    maxColUsedInRow.set(y, x);

                // Set the animation and use parent properties of the cell
                c.setAnimate(isInitialSetupFinished && willCellMove);
                c.setUseParentAsSource(!hasCellMoved);
{'fraction_non_alphanumeric': 0.07457601453664446, 'fraction_numerical': 0.006738340399757722, 'mean_word_length': 1.6360007982438636, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1876783', 'n_tokens_mistral': 3388, 'n_tokens_neox': 3095, 'n_words': 977}