Commit 15045f3c authored by Pedro Castro's avatar Pedro Castro

Initial patch from bug #607230 with minimal review

parent b697a0c7
......@@ -261,6 +261,9 @@
<File subtype="Code" buildaction="Compile" name="src/GnomeSubtitles/Core/Command/MergeSubtitlesCommand.cs" />
<File subtype="Code" buildaction="Compile" name="src/SubLib/Exceptions/FileTooLargeException.cs" />
<File subtype="Code" buildaction="Compile" name="src/GnomeSubtitles/Ui/Edit/SubtitleEditTextViewMargin.cs" />
<File subtype="Code" buildaction="Compile" name="src/GnomeSubtitles/Core/FileTools.cs" />
<File subtype="Code" buildaction="Compile" name="src/GnomeSubtitles/Ui/Component/FileCombo.cs" />
<File subtype="Code" buildaction="Compile" name="src/GnomeSubtitles/Ui/Component/FilexEncodingCombo.cs" />
</Contents>
<References>
<ProjectReference type="Gac" localcopy="True" refto="Mono.Posix, Version=2.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
......
......@@ -6,6 +6,7 @@ dnl Usage:
dnl GTK_DOC_CHECK([minimum-gtk-doc-version])
AC_DEFUN([GTK_DOC_CHECK],
[
AC_REQUIRE([PKG_PROG_PKG_CONFIG])
AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
......@@ -33,6 +34,11 @@ AC_DEFUN([GTK_DOC_CHECK],
AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))],
[PKG_CHECK_EXISTS([gtk-doc >= $1],,
AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build $PACKAGE_NAME]))])
dnl don't check for glib if we build glib
if test "x$PACKAGE_NAME" != "xglib"; then
dnl don't fail if someone does not have glib
PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,)
fi
fi
AC_MSG_CHECKING([whether to build gtk-doc documentation])
......
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<glade-interface>
<!-- interface-requires gtk+ 2.16 -->
<!-- interface-naming-policy toplevel-contextual -->
......@@ -11,60 +11,135 @@
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="has_separator">False</property>
<property name="select_multiple">True</property>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialogVBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">24</property>
<child>
<widget class="GtkTable" id="table">
<widget class="GtkTable" id="table3">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">2</property>
<property name="column_spacing">10</property>
<property name="row_spacing">10</property>
<property name="n_rows">3</property>
<property name="n_columns">4</property>
<property name="column_spacing">5</property>
<property name="row_spacing">2</property>
<child>
<widget class="GtkComboBox" id="videoComboBox">
<property name="items" translatable="yes"></property>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkLabel" id="subtitleFileLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Subtitle File:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="subtitleFileComboBox">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="videoLabel">
<widget class="GtkComboBox" id="subtitleEncodingComboBox">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="x_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="subtitleEncodingLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Character Encoding:</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="translationFileLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Video To Open:</property>
<property name="label" translatable="yes">Translation File:</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="encodingLabel">
<widget class="GtkLabel" id="videoFileLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Character Coding:</property>
<property name="label" translatable="yes">Video File:</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="fileEncodingComboBox">
<widget class="GtkLabel" id="translationEncodingLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Character Encoding:</property>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="translationFileComboBox">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="videoFileComboBox">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="translationEncodingComboBox">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
</packing>
</child>
</widget>
......
......@@ -154,6 +154,19 @@
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="translationAutoChooseFileCheckButton">
<property name="label" translatable="yes">Automatically choose the translation _file to open</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
<property name="position">2</property>
</packing>
</child>
</widget>
</child>
</widget>
......
......@@ -25,7 +25,6 @@ using Gtk;
using Mono.Unix;
using SubLib.Core.Domain;
using System;
using System.IO;
using System.Text;
namespace GnomeSubtitles.Core {
......
......@@ -32,6 +32,7 @@ public enum ConfigFileSaveEncoding { KeepExisting = -1, CurrentLocale = 0, Fixed
public enum ConfigFileSaveFormatOption { KeepExisting = 0, RememberLastUsed = 1, Specific = 3 }; //Values match ordering where the options are used
public enum ConfigFileSaveFormat { KeepExisting = -1, Fixed = 0 }; //KeepExisting=-1 because it doesn't appear
public enum ConfigFileSaveNewlineOption { RememberLastUsed = 0, Specific = 2 }; //Values match ordering where the options are used
public enum ValidFileTypes { Subtitle = 3, Video = 2, None = 0};
public class Config {
private Client client = null;
......@@ -53,6 +54,7 @@ public class Config {
private const string keyPrefsEncodingsShownInMenu = keyPrefsEncodings + "shown_in_menu";
private const string keyPrefsTranslationSaveAll = keyPrefsTranslation + "save_all";
private const string keyPrefsVideoAutoChooseFile = keyPrefsVideo + "auto_choose_file";
private const string keyPrefsTranslationAutoChooseFile = keyPrefsTranslation + "auto_choose_file";
private const string keyPrefsVideoApplyReactionDelay = keyPrefsVideo + "apply_reaction_delay";
private const string keyPrefsVideoReactionDelay = keyPrefsVideo + "reaction_delay";
private const string keyPrefsVideoSeekOnChange = keyPrefsVideo + "seek_on_change";
......@@ -125,6 +127,11 @@ public class Config {
get { return GetBool(keyPrefsVideoAutoChooseFile, true); }
set { Set(keyPrefsVideoAutoChooseFile, value); }
}
public bool PrefsTranslationAutoChooseFile {
get { return GetBool(keyPrefsTranslationAutoChooseFile, true); }
set { Set(keyPrefsTranslationAutoChooseFile, value); }
}
public bool PrefsVideoApplyReactionDelay {
get {
......
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using GnomeSubtitles.Core;
using SubLib.Core.Domain;
namespace GnomeSubtitles.Core
{
/// <summary>
/// !ThreadSafe in any way
/// </summary>
public class FileTools
{
private static Regex languageIdRegex = new Regex(@"[a-z][a-z]_[a-z][a-z]");
private static Regex subtitleFileExtentionsRegex = new Regex(BuildExtentionsPattern());
private static Regex videoFilesRegex = new Regex(@"^.*\.((3g2)|(3gp)|(asf)|(avi)|(bdm)|(cpi)|(divx)|(flv)|(m4v)|(mkv)|(mod)|(mov)|(mp3)|(mp4)|(mpeg)|(mpg)|(mts)|(ogg)|(ogm)|(rm)|(rmvb)|(spx)|(vob)|(wav)|(wma)|(wmv)|(xvid))$");
/*Public Funtions */
/// <summary>
/// Returns an collection of strings containing any files matching the type specified, Returns null if path is incorrect or empty list if no files of type found
/// </summary>
/// <param name="path">
/// A <see cref="System.String"/>
/// </param>
/// <param name="type">
/// A <see cref="ValidFileTypes"/>
/// </param>
/// <returns>
/// A <see cref="IEnumerable<System.String>"/>
/// </returns>
public static IEnumerable<string> GetFilesOfType (string path, ValidFileTypes type) {
if ((path == null) || (path == String.Empty) || (!Directory.Exists(path)) )
return null;
string[] allFiles = Directory.GetFiles(path, "*.*");
return GetFilesOfType(allFiles, type);
}
/// <summary>
/// Returns a collection of strings containing all string paths or filenames from supplied collection that match specified type
/// </summary>
/// <param name="filepaths">
/// A <see cref="System.String[]"/>
/// </param>
/// <param name="type">
/// A <see cref="ValidFileTypes"/>
/// </param>
/// <returns>
/// A <see cref="IEnumerable<System.String>"/>
/// </returns>
public static IEnumerable<string> GetFilesOfType (IEnumerable<string> filepaths, ValidFileTypes type) {
List<string> returnfiles = new List<string>();
foreach (string filepath in filepaths) {
if (GetFileType(filepath) == type) {
returnfiles.Add(filepath);
}
}
returnfiles.Sort();
return returnfiles;
}
/// <summary>
/// Finds closest match available in given files parent folder that is of the specified type, Returns null if no match is found
/// </summary>
/// <param name="path">
/// A <see cref="System.String"/>
/// </param>
/// <param name="type">
/// A <see cref="ValidFileTypes"/>
/// </param>
/// <returns>
/// A <see cref="System.String"/>
/// </returns>
public static string FromFolderFindMatchOfType (string filepath, ValidFileTypes type) {
return FindMatchingFile(filepath, GetFilesOfType(filepath, type));
}
/// <summary>
/// Finds nearest match to supplied filename in given collection of files, Returns null if no match is found
/// </summary>
/// <param name="filetomatch">
/// A <see cref="System.String"/>
/// </param>
/// <param name="filestosearch">
/// A <see cref="IEnumerable<System.String>"/>
/// </param>
/// <returns>
/// A <see cref="System.String"/>
/// </returns>
public static string FindMatchingFile (string filetomatch, IEnumerable<string> filestosearch) {
string filenametomatch = GetCleanFilenamePattern(filetomatch);
string currentcultureid = FilenameContainsLanguageId(filetomatch) ? GetFilenameLanguageId(filetomatch) : CultureInfo.CurrentUICulture.Name;
List<string> matchingfiles = new List<string>();
List<string> matchingfileswithid = new List<string>();
List<string> matchingforeignfileswithid = new List<string>();
foreach(string file in filestosearch) {
string filename = Path.GetFileName(file);
if (Regex.IsMatch(filename, filenametomatch) && file != filetomatch)
matchingfiles.Add(file);
}
if (matchingfiles.Count > 0) {
foreach(string matchingfile in matchingfiles) {
if (FilenameContainsLanguageId(matchingfile))
matchingfileswithid.Add(matchingfile);
}
if (matchingfileswithid.Count > 0) {
foreach (string matchingfilewithid in matchingfileswithid) {
if (GetFilenameLanguageId(matchingfilewithid) != currentcultureid)
matchingforeignfileswithid.Add(matchingfilewithid);
}
if (matchingforeignfileswithid.Count > 0){
return matchingforeignfileswithid[0];
} else {
return matchingfileswithid[0];
}
} else {
return matchingfiles[0];
}
} return null;
}
/// <summary>
/// Simply bolts on "file://" to given string and returns as uri
/// </summary>
/// <param name="filepath">
/// A <see cref="System.String"/>
/// </param>
/// <returns>
/// A <see cref="Uri"/>
/// </returns>
public static Uri GetUriFromFilePath (string filepath) {
return new Uri ("file://" + filepath);
}
/*Private Functions */
private static string BuildExtentionsPattern () {
SubtitleTypeInfo[] types = Subtitles.AvailableTypesSorted;
StringBuilder pattern = new StringBuilder(@"^.*\.(");
foreach(SubtitleTypeInfo type in types) {
foreach (string extention in type.Extensions)
pattern.Append("(").Append(extention).Append(")|");
}
pattern.Remove(pattern.Length -1, 1); //remove last "|"
pattern.Append(")$");
return pattern.ToString();
}
private static bool FileIsSubtitle (string file) {
return (subtitleFileExtentionsRegex.IsMatch(Path.GetExtension(file)));
}
private static bool FileIsVideo (string file) {
return videoFilesRegex.IsMatch(file);
}
private static bool FilenameContainsLanguageId (string file) {
return (languageIdRegex.IsMatch(file));
}
/// <summary>
/// Returns a filetype based on a simple file extention regex test
/// </summary>
/// <param name="file">
/// A <see cref="System.String"/>
/// </param>
/// <returns>
/// A <see cref="ValidFileTypes"/>
/// </returns>
private static ValidFileTypes GetFileType (string file) {
if (FileTools.FileIsSubtitle(file)) {
return ValidFileTypes.Subtitle;
} else if (FileTools.FileIsVideo(file)) {
return ValidFileTypes.Video;
} else {
return ValidFileTypes.None;
}
}
private static string GetFilenameLanguageId (string candidate) {
if (FilenameContainsLanguageId(candidate)){
foreach (SpellLanguage lang in Base.SpellLanguages.Languages) {
if(lang.StringMatchesId(candidate))
return lang.ID;
}
}
return String.Empty;
}
/// <summary>
/// Attempts to remove any tags added by Gnome-Subtitles and escape any regex wildcards from a string filepath or filename
/// </summary>
/// <param name="filename">
/// A <see cref="System.String"/>
/// </param>
/// <returns>
/// A <see cref="System.String"/>
/// </returns>
private static string GetCleanFilenamePattern (string filename) {
filename = Path.GetFileNameWithoutExtension(filename);
if (GetFilenameLanguageId(filename) != String.Empty)
filename.Replace(GetFilenameLanguageId(filename), "");
filename = Regex.Escape(filename);
filename.Trim();
return filename;
}
}
}
......@@ -49,6 +49,12 @@ public class SpellLanguage : IComparable {
get { return name; }
}
public bool StringMatchesId (string candidate) {
if (regex.IsMatch(candidate))
return true;
return false;
}
/* Public methods */
public override bool Equals (object o) {
......
......@@ -16,77 +16,73 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
using System;
using System.Collections.Generic;
using System.IO;
using Glade;
using GnomeSubtitles.Core;
using GnomeSubtitles.Ui.Component;
using GnomeSubtitles.Ui.VideoPreview;
using Glade;
using Gtk;
using Mono.Unix;
using SubLib.Core.Domain;
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace GnomeSubtitles.Dialog {
public class FileOpenDialog : GladeDialog {
protected FileChooserDialog dialog = null;
private string chosenFilename = String.Empty;
private EncodingDescription chosenEncoding = EncodingDescription.Empty;
private ArrayList videoFiles = null; //The full paths of the video files in the current dir
private ArrayList videoFilenames = null; //The filenames of videoFiles, without extensions
private Uri chosenVideoUri = null;
private bool autoChooseVideoFile = true;
/* Preferences */
protected bool autoChooseVideoFile = true;
protected bool autoChooseTranslationFile = true;
protected List<string> subtitleFiles = new List<string>();
protected List<string> videoFiles = new List<string>();
protected List<FilexEncodingCombo> ActiveSelectionCombos = new List<FilexEncodingCombo>();
/* Constant strings */
private const string gladeFilename = "FileOpenDialog.glade";
/* Components */
private EncodingComboBox encodingComboBox = null;
protected FilexEncodingCombo selectedSubtitle = null;
protected FilexEncodingCombo selectedTranslation = null;
protected FileCombo selectedVideo = null;
/* Widgets */
[WidgetAttribute] private ComboBox fileEncodingComboBox = null;
[WidgetAttribute] private ComboBox videoComboBox = null;
[WidgetAttribute] private Label videoLabel = null;
[WidgetAttribute] protected Label subtitleFileLabel = null;
[WidgetAttribute] protected ComboBox subtitleFileComboBox = null;
[WidgetAttribute] protected ComboBox subtitleEncodingComboBox = null;
[WidgetAttribute] protected Label translationFileLabel = null;
[WidgetAttribute] protected ComboBox translationFileComboBox = null;
[WidgetAttribute] protected ComboBox translationEncodingComboBox = null;
[WidgetAttribute] protected Label videoFileLabel = null;
[WidgetAttribute] protected ComboBox videoFileComboBox = null;
public FileOpenDialog () : this(true, Catalog.GetString("Open File")) {
public FileOpenDialog () : this(true, true ,Catalog.GetString("Open Files")) {
}
protected FileOpenDialog (bool toEnableVideo, string title) : base(gladeFilename) {
protected FileOpenDialog (bool toEnableVideo, bool toEnableTranslation, string title) : base(gladeFilename) {
dialog = GetDialog() as FileChooserDialog;
dialog.Title = title;
InitEncodingComboBox();
if (toEnableVideo)
dialog.CurrentFolderChanged += OnCurrentFolderChangedGetTextFiles;
dialog.SelectionChanged += OnSelectionGetTextFiles;
InitSelectedSubtitleCombo (); // this is overriden in TranslationFileOpen
if (toEnableTranslation) {
InitSelectedTranslationCombo ();
}
if (toEnableVideo) // This must be enabled last to allow autoselection to funtion
EnableVideo();
string startFolder = GetStartFolder();
dialog.SetCurrentFolder(startFolder);
SetFilters();
}
private void InitEncodingComboBox () {
int fixedEncoding = -1;
ConfigFileOpenEncoding encodingConfig = Base.Config.PrefsDefaultsFileOpenEncoding;
if (encodingConfig == ConfigFileOpenEncoding.Fixed) {
string encodingName = Base.Config.PrefsDefaultsFileOpenEncodingFixed;
EncodingDescription encodingDescription = EncodingDescription.Empty;
Encodings.Find(encodingName, ref encodingDescription);
fixedEncoding = encodingDescription.CodePage;
}
this.encodingComboBox = new EncodingComboBox(fileEncodingComboBox, true, null, fixedEncoding);
/* Only need to handle the case of currentLocale, as Fixed is handled before and AutoDetect is the default behaviour */
if (encodingConfig == ConfigFileOpenEncoding.CurrentLocale)
encodingComboBox.ActiveSelection = (int)encodingConfig;
SetFilters();
}
/* Overriden members */
......@@ -96,23 +92,26 @@ public class FileOpenDialog : GladeDialog {
}
/* Public properties */
public EncodingDescription Encoding {
get { return chosenEncoding; }
public string SelectedSubtitle {
get { return selectedSubtitle != null ? selectedSubtitle.ActiveSelection : null;}
}
public string Filename {
get { return chosenFilename; }
public EncodingDescription SelectedSubtitleEncoding {
get { return selectedSubtitle != null ? selectedSubtitle.SelectedEncoding : EncodingDescription.Empty;}
}
public bool HasVideoFilename {
get { return chosenVideoUri != null; }
public string SelectedTranslation {
get { return selectedTranslation != null ? selectedTranslation.ActiveSelection : null;}
}
public Uri VideoUri {
get { return chosenVideoUri; }
public EncodingDescription SelectedTranslationEncoding {
get { return selectedTranslation != null ? selectedTranslation.SelectedEncoding : EncodingDescription.Empty;}
}