[gnome-subtitles: 1/6] #2 Split improvements Split improvements: split all lines (previously were split into 2 halves) and



commit 5000ab00dd7aacc4735962f3575e3b63595bd649
Author: Pedro Castro <pedro gnomesubtitles org>
Date:   Sat May 4 19:35:27 2019 +0100

    #2 Split improvements
    Split improvements: split all lines (previously
    were split into 2 halves) and only split subtitles
    with multiple lines

 src/Glade/MainWindow.ui                            |   4 +-
 .../Core/Command/SplitSubtitlesCommand.cs          |  45 +++---
 src/SubLib/Core/Domain/SubtitleText.cs             |   3 +-
 src/SubLib/Core/Timing/SplitOperator.cs            | 172 ++++++++++++---------
 4 files changed, 127 insertions(+), 97 deletions(-)
---
diff --git a/src/Glade/MainWindow.ui b/src/Glade/MainWindow.ui
index 4d4f662..e4ca82e 100644
--- a/src/Glade/MainWindow.ui
+++ b/src/Glade/MainWindow.ui
@@ -351,7 +351,7 @@
                       <object class="GtkMenuItem" id="editSplit">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_Split</property>
+                        <property name="label" translatable="yes">_Split Lines</property>
                         <property name="use_underline">True</property>
                         <signal name="activate" handler="OnEditSplit" swapped="no"/>
                         <accelerator key="m" signal="activate" modifiers="GDK_SHIFT_MASK | 
GDK_CONTROL_MASK"/>
@@ -361,7 +361,7 @@
                       <object class="GtkMenuItem" id="editMerge">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">_Merge</property>
+                        <property name="label" translatable="yes">_Merge Lines</property>
                         <property name="use_underline">True</property>
                         <signal name="activate" handler="OnEditMerge" swapped="no"/>
                         <accelerator key="m" signal="activate" modifiers="GDK_CONTROL_MASK"/>
diff --git a/src/GnomeSubtitles/Core/Command/SplitSubtitlesCommand.cs 
b/src/GnomeSubtitles/Core/Command/SplitSubtitlesCommand.cs
index 5bde4dd..0ac685f 100644
--- a/src/GnomeSubtitles/Core/Command/SplitSubtitlesCommand.cs
+++ b/src/GnomeSubtitles/Core/Command/SplitSubtitlesCommand.cs
@@ -1,6 +1,6 @@
 /*
  * This file is part of Gnome Subtitles.
- * Copyright (C) 2017 Pedro Castro
+ * Copyright (C) 2017-2019 Pedro Castro
  *
  * Gnome Subtitles is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ public class SplitSubtitlesCommand : MultipleSelectionCommand {
        }
 
        public override bool Execute () {
-               GnomeSubtitles.Ui.View.Subtitles subtitles = Base.Document.Subtitles;
+               Ui.View.Subtitles subtitles = Base.Document.Subtitles;
                ArrayList pathsBefore = new ArrayList();
                ArrayList subtitlesBefore = new ArrayList();
                ArrayList pathsAfter = new ArrayList();
@@ -44,33 +44,34 @@ public class SplitSubtitlesCommand : MultipleSelectionCommand {
                SplitOperator splitOperator = new SplitOperator(subtitles, 
Base.Config.TimingsTimeBetweenSubtitles);
 
                foreach (TreePath path in Paths) {
-                       int subtitleIndex = Util.PathToInt(path) + subtitlesBefore.Count; //need to account 
for subtitles already added in this loop
+                       int subtitlesThatHaveBeenAdded = pathsAfter.Count - pathsBefore.Count; //number of 
subtitles that have been added ever since, in this loop
+                       int subtitleIndex = Util.PathToInt(path) + subtitlesThatHaveBeenAdded;
                        Subtitle subtitle = subtitles[subtitleIndex];
-                       Subtitle subtitleClone = subtitle.Clone(subtitles.Properties);
-                       Subtitle subtitle2 = splitOperator.Split(subtitle);
-                       if (subtitle2 != null) {
-                               pathsAfter.Add(Util.IntToPath(subtitleIndex));
-                               pathsAfter.Add(Util.IntToPath(subtitleIndex + 1));
-
+                       
+                       Subtitle[] newSubtitles = splitOperator.Split(subtitle);
+                       if (newSubtitles != null) {
                                pathsBefore.Add(path);
-                               subtitlesBefore.Add(subtitleClone);
-
-                               subtitles.Add(subtitle2, subtitleIndex + 1);
+                               subtitlesBefore.Add(subtitle);
+                               
+                               subtitles.Remove(subtitleIndex);
+                               for (int i = 0 ; i < newSubtitles.Length ; i++) {
+                                       pathsAfter.Add(Util.IntToPath(subtitleIndex + i));
+                                       subtitles.Add(newSubtitles[i], subtitleIndex + i);
+                               }
                        }
                }
 
-               /* If any subtitle was changed, the command was successful */
-               if (subtitlesBefore.Count == 0)
+               if (subtitlesBefore.Count == 0) {
                        return false;
-               else {
-                       this.subtitlesBefore = (Subtitle[])subtitlesBefore.ToArray(typeof(Subtitle));
-                       this.Paths = (TreePath[])pathsBefore.ToArray(typeof(TreePath));
-                       this.pathsAfter = (TreePath[])pathsAfter.ToArray(typeof(TreePath));
-                       Base.Ui.View.RedrawPaths(this.pathsAfter);
-                       Base.Ui.View.Selection.Select(this.pathsAfter, this.pathsAfter[0], true);
-                       PostProcess();
-                       return true;
                }
+               
+               this.subtitlesBefore = (Subtitle [])subtitlesBefore.ToArray(typeof(Subtitle));
+               this.Paths = (TreePath [])pathsBefore.ToArray(typeof(TreePath));
+               this.pathsAfter = (TreePath [])pathsAfter.ToArray(typeof(TreePath));
+               Base.Ui.View.RedrawPaths(this.pathsAfter);
+               Base.Ui.View.Selection.Select(this.pathsAfter, this.pathsAfter [0], true);
+               PostProcess();
+               return true;
        }
 
        public override void Undo () {
diff --git a/src/SubLib/Core/Domain/SubtitleText.cs b/src/SubLib/Core/Domain/SubtitleText.cs
index 6000f31..812ab96 100644
--- a/src/SubLib/Core/Domain/SubtitleText.cs
+++ b/src/SubLib/Core/Domain/SubtitleText.cs
@@ -1,6 +1,6 @@
 /*
  * This file is part of SubLib.
- * Copyright (C) 2005-2011 Pedro Castro
+ * Copyright (C) 2005-2019 Pedro Castro
  *
  * SubLib is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,7 +19,6 @@
 
 using System;
 using System.Collections;
-using System.Text;
 using System.Text.RegularExpressions;
 
 namespace SubLib.Core.Domain {
diff --git a/src/SubLib/Core/Timing/SplitOperator.cs b/src/SubLib/Core/Timing/SplitOperator.cs
index be31573..d588924 100644
--- a/src/SubLib/Core/Timing/SplitOperator.cs
+++ b/src/SubLib/Core/Timing/SplitOperator.cs
@@ -1,6 +1,6 @@
 /*
  * This file is part of SubLib.
- * Copyright (C) 2011 Pedro Castro
+ * Copyright (C) 2011-2019 Pedro Castro
  *
  * SubLib is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
 
 using SubLib.Core.Domain;
 using System;
+using System.Collections;
 
 namespace SubLib.Core.Timing {
 
@@ -34,101 +35,130 @@ public class SplitOperator {
 
        /* Public members */
 
-       public Subtitle Split (Subtitle subtitle) {
-               if (!isOperationValid(subtitle))
+       public Subtitle[] Split (Subtitle subtitle) {
+               if (!IsOperationValid(subtitle))
                        return null;
 
-               Subtitle subtitle2 = Split(subtitle, this.subtitles.Properties, this.timeBetweenSubtitles);
-               return subtitle2;
+               return Split(subtitle, this.subtitles.Properties, this.timeBetweenSubtitles);
        }
 
 
        /* Private members */
 
-       /// <summary>Splits a subtitle in two halves. The subtitle passed as parameter is turned into the 
first half and the second half is returned.</summary>
+       /// <summary>Splits a single subtitle into multiple subtitles - one for each subtitle line.</summary>
        /// <param name="subtitle">The subtitle to split</param>
        /// <param name="subtitleProperties">The subtitle properties</param>
        /// <param name="timeBetweenSubtitles">Time between the 2 subtitles, in milliseconds</param>
-       private Subtitle Split (Subtitle subtitle, SubtitleProperties subtitleProperties, int 
timeBetweenSubtitles) {
-               Subtitle subtitle2 = subtitle.Clone(subtitleProperties);
+       private Subtitle[] Split (Subtitle subtitle, SubtitleProperties subtitleProperties, int 
timeBetweenSubtitles) {
 
-               /* Change timings */
+               //Get text lines
+               ArrayList textLines = GetTextLines(subtitle);
+               if (textLines == null) {
+                       return null;
+               }
+
+               //Get translation lines
+               ArrayList translationLines = GetAlignedTranslationLines(subtitle, textLines);
+               
+               //Prepare times. There must be at least
                int originalStart = (int)subtitle.Times.Start.TotalMilliseconds;
                int originalEnd = (int)subtitle.Times.End.TotalMilliseconds;
+               int originalDuration = originalEnd - originalStart;
+               
+               int newDuration = CalculateSubtitleDuration(originalDuration, timeBetweenSubtitles, 
textLines.Count);
+               if (newDuration < timeBetweenSubtitles) {
+                       timeBetweenSubtitles = 0; //If each subtitle would have a duration shorter than 
timeBetweenSubtitles itself, we don't use it
+                       newDuration = CalculateSubtitleDuration(originalDuration, timeBetweenSubtitles, 
textLines.Count);
+               }
+               
+               /* Create a new Subtitle for each line by cloning the original one and setting appropriate 
text and times.
+                * Note: textLines can have a single line (which means the other original lines were empty). 
In this case,
+                * the subtitle will still be changed as a form of "cleanup" where the empty lines are 
removed.
+                */
+               ArrayList result = new ArrayList();
+               for (int i = 0; i < textLines.Count; i++) {
+                       Subtitle newSubtitle = subtitle.Clone(subtitleProperties);
+                       
+                       //Set text
+                       newSubtitle.Text.Set(textLines[i] as String);
+                       
+                       //Set translation
+                       if (subtitle.HasTranslation) {
+                               if (i < translationLines.Count) { 
+                                       newSubtitle.Translation.Set(translationLines[i] as String);
+                               } else {
+                                       newSubtitle.Translation.Clear();
+                               }
+                       }
+                       
+                       int start = originalStart + i * (newDuration + timeBetweenSubtitles);
+                       newSubtitle.Times.Start = TimeSpan.FromMilliseconds(start);
+                       newSubtitle.Times.End = TimeSpan.FromMilliseconds(start + newDuration);
 
-               if ((originalEnd - originalStart) <= timeBetweenSubtitles) {
-                       /* Not possible to have the predefined time between subtitle, subtitle 2 will start 
at subtitle's end time */
-                       int originalMiddle = (originalStart + originalEnd) / 2;
-                       TimeSpan newSubtitleEnd = TimeSpan.FromMilliseconds(originalMiddle);
-                       subtitle.Times.End = newSubtitleEnd;
-                       subtitle2.Times.Start = newSubtitleEnd;
+                       result.Add(newSubtitle);
                }
-               else {
-                       int newSubtitleEnd = (originalStart + originalEnd - timeBetweenSubtitles) / 2;
-                       int subtitle2Start = newSubtitleEnd + timeBetweenSubtitles;
-                       subtitle.Times.End = TimeSpan.FromMilliseconds(newSubtitleEnd);
-                       subtitle2.Times.Start = TimeSpan.FromMilliseconds(subtitle2Start);
+               
+               return (Subtitle[])result.ToArray(typeof(Subtitle));
+       }
+       
+       private ArrayList GetTextLines (Subtitle subtitle) {
+               //Check if we have multiple text lines in this subtitle. If we don't, just return.
+               string[] originalLines = subtitle.Text.GetLines();
+               if ((originalLines == null) || (originalLines.Length <= 1)) {
+                       return null;
                }
 
-               /* Change subtitle text */
-               string[] textLines = subtitle.Text.GetLines();
-               if (textLines.Length == 1)
-                       subtitle2.Text.Clear();
-               else if (textLines.Length > 1) {
-                       string[] textLinesHalf1 = null;
-                       string[] textLinesHalf2 = null;
-                       SplitArray(textLines, ref textLinesHalf1, ref textLinesHalf2);
-                       subtitle.Text.Set(textLinesHalf1);
-                       subtitle2.Text.Set(textLinesHalf2);
+               //Remove empty or whitespace text lines.
+               ArrayList textLines = GetNonEmptyLines(originalLines);
+               if (textLines.Count == 0) {
+                       return null;
                }
+               
+               return textLines;
+       }
 
-               /* Change translation text */
-               if (subtitle.HasTranslation) {
-                       string[] translationLines = subtitle.Translation.GetLines();
-                       if (translationLines.Length == 1)
-                               subtitle2.Translation.Clear();
-                       else if (translationLines.Length > 1) {
-                               string[] translationLinesHalf1 = null;
-                               string[] translationLinesHalf2 = null;
-                               SplitArray(translationLines, ref translationLinesHalf1, ref 
translationLinesHalf2);
-                               subtitle.Translation.Set(translationLinesHalf1);
-                               subtitle2.Translation.Set(translationLinesHalf2);
-                       }
+       private ArrayList GetAlignedTranslationLines (Subtitle subtitle, ArrayList textLines) {
+               if (!subtitle.HasTranslation) {
+                       return null;
+               }
+               
+               string[] originalLines = subtitle.Translation.GetLines();
+               if (originalLines == null) {
+                       return null;
                }
 
-               return subtitle2;
+               //Remove empty or whitespace text lines.
+               ArrayList translationLines = GetNonEmptyLines(originalLines);
+               if (translationLines.Count > textLines.Count) {
+                       int lastTextIndex = textLines.Count - 1;
+                       String lastLine = String.Join("\n", 
(string[])translationLines.ToArray(typeof(string)), lastTextIndex, translationLines.Count - textLines.Count + 
1);
+                       translationLines[lastTextIndex] = lastLine;
+                       translationLines.RemoveRange(lastTextIndex + 1, translationLines.Count - 
textLines.Count);
+               }
+               
+               return translationLines;
+       }
+       
+       private ArrayList GetNonEmptyLines (string[] lines) {
+               ArrayList result = new ArrayList();
+               
+               foreach (string line in lines) {
+                       if (!String.IsNullOrWhiteSpace(line)) {
+                               result.Add(line);
+                       }
+               }
+               
+               return result;
+       }
+       
+       private int CalculateSubtitleDuration (int originalDuration, int timeBetweenSubtitles, int lineCount) 
{
+               return (originalDuration - (timeBetweenSubtitles * (lineCount - 1))) / lineCount;
        }
 
-       private bool isOperationValid (Subtitle subtitle) {
+       private bool IsOperationValid (Subtitle subtitle) {
                return subtitle.Times.End >= subtitle.Times.Start;
        }
 
-       private void SplitArray<T> (T[] array, ref T[] half1, ref T[] half2) {
-               if (array == null) {
-                       half1 = null;
-                       half2 = null;
-                       return;
-               }
-
-               int arrayLength = array.Length;
-               if (arrayLength == 0) {
-                       half1 = new T[0];
-                       half2 = new T[0];
-               }
-               else if (arrayLength == 1) {
-                       half1 = new T[1];
-                       half1[0] = array[0];
-                       half2 = new T[0];
-               }
-               else {
-                       int half1Length = (int)Math.Round(arrayLength / 2d);
-                       int half2Length = arrayLength - half1Length;
-                       half1 = new T[half1Length];
-                       half2 = new T[half2Length];
-                       Array.Copy(array, 0, half1, 0, half1Length);
-                       Array.Copy(array, half1Length, half2, 0, half2Length);
-               }
-       }
 }
 
-}
+}
\ No newline at end of file


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]