actually implement AutoSave plugin, and add NonSerializedProperty where appropriate to FileSystem objects

This commit is contained in:
Michael Becker 2021-01-09 22:41:27 -05:00
parent 97c9e605c4
commit f439eb6513
No known key found for this signature in database
GPG Key ID: 98C333A81F18C22C
13 changed files with 697 additions and 46 deletions

View File

@ -0,0 +1,36 @@
//
// NonSerializedPropertyAttribute.cs - indicates that a particular property should not be serialized
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2011-2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor
{
/// <summary>
/// Indicates that a particular property should not be serialized. Used in
/// place of <see cref="NonSerializedAttribute" /> because that does
/// not allow use on property declarations.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NonSerializedPropertyAttribute : Attribute
{
}
}

View File

@ -126,23 +126,20 @@ namespace UniversalEditor.ObjectModels.FileSystem
}
}
private FileAttributes mvarAttributes = FileAttributes.None;
public FileAttributes Attributes { get { return mvarAttributes; } set { mvarAttributes = value; } }
private string mvarName = String.Empty;
public FileAttributes Attributes { get; set; } = FileAttributes.None;
/// <summary>
/// The name of this file.
/// </summary>
public string Name { get { return mvarName; } set { mvarName = value; } }
public string Name { get; set; } = String.Empty;
public void SetData(byte[] data)
{
mvarSource = new MemoryFileSource(data);
Source = new MemoryFileSource(data);
}
public byte[] GetData()
{
if (mvarSource != null) return mvarSource.GetData();
if (Source != null) return Source.GetData();
if (DataRequest != null)
{
DataRequestEventArgs e = new DataRequestEventArgs();
@ -150,15 +147,15 @@ namespace UniversalEditor.ObjectModels.FileSystem
return e.Data;
}
Console.WriteLine("DataRequest: " + mvarName + ": No source associated with this file");
Console.WriteLine("DataRequest: " + Name + ": No source associated with this file");
return new byte[0];
}
public byte[] GetData(long offset, long length)
{
if (mvarSource != null) return mvarSource.GetDataInternal(offset, length);
if (Source != null) return Source.GetDataInternal(offset, length);
Console.WriteLine("DataRequest: " + mvarName + ": No source associated with this file");
Console.WriteLine("DataRequest: " + Name + ": No source associated with this file");
return new byte[length];
}
@ -170,7 +167,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
}
public void SetData(System.IO.Stream stream)
{
mvarSource = new AccessorFileSource(new StreamAccessor(stream));
Source = new AccessorFileSource(new StreamAccessor(stream));
}
public void SetData(string value)
@ -185,14 +182,14 @@ namespace UniversalEditor.ObjectModels.FileSystem
public object Clone()
{
File clone = new File();
clone.Name = mvarName;
clone.Source = mvarSource;
clone.Name = Name;
clone.Source = Source;
if (DataRequest != null)
{
clone.DataRequest += DataRequest;
}
clone.Source = Source;
foreach (KeyValuePair<string, object> kvp in mvarProperties)
foreach (KeyValuePair<string, object> kvp in Properties)
{
clone.Properties.Add(kvp.Key, kvp.Value);
}
@ -200,7 +197,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
{
clone.AdditionalDetails.Add(kvp.Key, kvp.Value);
}
clone.Parent = mvarParent;
clone.Parent = Parent;
return clone;
}
@ -266,7 +263,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
strSize = "?";
}
}
return mvarName + " [" + strSize + "]";
return Name + " [" + strSize + "]";
}
public void Save()
@ -281,7 +278,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
System.IO.Directory.CreateDirectory(FileDirectory);
}
FileSource source = mvarSource;
FileSource source = Source;
long blockSize = (System.Environment.WorkingSet / 8);
long blockCount = (blockSize / source.GetLength());
long offset = 0;
@ -310,9 +307,9 @@ namespace UniversalEditor.ObjectModels.FileSystem
}
else
{
if (mvarSource != null)
if (Source != null)
{
return mvarSource.GetLength();
return Source.GetLength();
}
return 0;
}
@ -328,31 +325,23 @@ namespace UniversalEditor.ObjectModels.FileSystem
mvarSize = null;
}
#region Metadata
private string mvarTitle = null;
public string Title { get { return mvarTitle; } set { mvarTitle = value; } }
private string mvarDescription = null;
public string Description { get { return mvarDescription; } set { mvarDescription = value; } }
#endregion
public string Title { get; set; } = null;
public string Description { get; set; } = null;
public event DataRequestEventHandler DataRequest;
private Dictionary<string, object> mvarProperties = new Dictionary<string, object>();
public Dictionary<string, object> Properties { get { return mvarProperties; } }
public Dictionary<string, object> Properties { get; } = new Dictionary<string, object>();
public DateTime ModificationTimestamp { get; set; } = DateTime.Now;
private DateTime mvarModificationTimestamp = DateTime.Now;
public DateTime ModificationTimestamp { get { return mvarModificationTimestamp; } set { mvarModificationTimestamp = value; } }
private FileSource mvarSource = null;
/// <summary>
/// Determines where this <see cref="File" /> gets its data from.
/// </summary>
public FileSource Source { get { return mvarSource; } set { mvarSource = value; } }
public FileSource Source { get; set; } = null;
private IFileSystemContainer mvarParent = null;
public IFileSystemContainer Parent { get { return mvarParent; } internal set { mvarParent = value; } }
[NonSerializedProperty]
public IFileSystemContainer Parent { get; internal set; } = null;
[NonSerializedProperty]
public FileSystemObjectModel FileSystem { get; private set; } = null;
// The amount of working set to allocate to each block.
@ -370,7 +359,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
long blockSize = (System.Environment.SystemPageSize / BLOCK_FRACTION);
long offset = 0;
double dbl = ((double)mvarSource.GetLength() / (double)blockSize);
double dbl = ((double)Source.GetLength() / (double)blockSize);
long blockCount = (long)Math.Ceiling(dbl);
if (transformations != null)
@ -380,7 +369,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
for (long i = 0; i < blockCount; i++)
{
byte[] data = mvarSource.GetDataInternal(offset, blockSize);
byte[] data = Source.GetDataInternal(offset, blockSize);
offset += blockSize;
bw.WriteBytes(data);

View File

@ -66,7 +66,10 @@ namespace UniversalEditor.ObjectModels.FileSystem
}
}
[NonSerializedProperty]
public FileSystemObjectModel FileSystem { get { return this; } }
[NonSerializedProperty]
public IFileSystemContainer Parent { get { return null; } }
public static FileSystemObjectModel FromFiles(string[] fileNames)
{
@ -192,9 +195,9 @@ namespace UniversalEditor.ObjectModels.FileSystem
}
}
public object FindObject(string name)
public IFileSystemObject FindObject(string name)
{
string[] path = name.Split(new char[] { '/' });
string[] path = name.Split(new char[] { '/', '\\' });
Folder parent = null;
for (int i = 0; i < path.Length - 1; i++)
{

View File

@ -106,6 +106,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
mvarFiles = new File.FileCollection(this);
}
[NonSerializedProperty]
public FileSystemObjectModel FileSystem { get; private set; } = null;
private FolderCollection _parentCollection = null;
@ -113,8 +114,8 @@ namespace UniversalEditor.ObjectModels.FileSystem
private string mvarName = String.Empty;
public string Name { get { return mvarName; } set { mvarName = value; } }
private IFileSystemContainer mvarParent = null;
public IFileSystemContainer Parent { get { return mvarParent; } private set { mvarParent = value; } }
[NonSerializedProperty]
public IFileSystemContainer Parent { get; private set; } = null;
private FolderCollection mvarFolders = null;
public FolderCollection Folders { get { return mvarFolders; } }

View File

@ -24,15 +24,12 @@ namespace UniversalEditor.ObjectModels.FileSystem
/// <summary>
/// The interface which defines the base functionality for an object which contains <see cref="File" />s and <see cref="Folder" />s.
/// </summary>
public interface IFileSystemContainer
public interface IFileSystemContainer : IFileSystemObject
{
File.FileCollection Files { get; }
Folder.FolderCollection Folders { get; }
string GetNewFolderName();
File AddFile(string name, byte[] fileData = null);
FileSystemObjectModel FileSystem { get; }
string Name { get; set; }
}
}

View File

@ -29,6 +29,7 @@ namespace UniversalEditor.ObjectModels.FileSystem
string Name { get; set; }
FileSystemObjectModel FileSystem { get; }
IFileSystemContainer Parent { get; }
}
/// <summary>
/// Represents a <see cref="System.Collections.ObjectModel.Collection{IFileSystemObject}" /> of <see cref="IFileSystemObject" />s.

View File

@ -0,0 +1,251 @@
using System;
using System.Reflection;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
namespace UniversalEditor.Plugins.AutoSave
{
internal class AutoSaveDataFormat : DataFormat
{
public float Version { get; set; } = 1.0f;
public static float MAX_SUPPORTED_VERSION = 1.0f;
protected override void LoadInternal(ref ObjectModel objectModel)
{
Reader r = Accessor.Reader;
AutoSaveObjectModel autosave = (objectModel as AutoSaveObjectModel);
string signature = r.ReadFixedLengthString(12);
if (!signature.Equals("UE4 AutoSave"))
throw new InvalidDataFormatException("file does not begin with 'UE4 AutoSave'");
Version = r.ReadSingle();
if (Version > MAX_SUPPORTED_VERSION)
{
throw new InvalidDataFormatException(String.Format("format version {0} not supported!", Version));
}
autosave.OriginalFileName = r.ReadNullTerminatedString();
autosave.LastUpdateDateTime = r.ReadDateTime();
long offsetToStringTable = r.ReadInt64();
r.Accessor.SavePosition();
r.Seek(offsetToStringTable, SeekOrigin.Begin);
int stringTableCount = r.ReadInt32();
for (int i = 0; i < stringTableCount; i++)
{
string value = r.ReadNullTerminatedString();
_StringTable.Add(value);
}
r.Accessor.LoadPosition();
object om = ReadObject(r);
if (om is ObjectModel)
{
autosave.ObjectModel = (om as ObjectModel);
}
}
protected override void SaveInternal(ObjectModel objectModel)
{
Writer w = Accessor.Writer;
AutoSaveObjectModel autosave = (objectModel as AutoSaveObjectModel);
w.AutoFlush = true; // should be removed for release
w.WriteFixedLengthString("UE4 AutoSave");
w.WriteSingle(Version);
if (autosave.OriginalFileName != null)
{
w.WriteNullTerminatedString(autosave.OriginalFileName);
}
else
{
w.WriteByte(0);
}
// last update date time
w.WriteDateTime(DateTime.Now);
MemoryAccessor ma = new MemoryAccessor();
WriteObject(ma.Writer, autosave.ObjectModel);
ma.Flush();
ma.Close();
w.WriteInt64(ma.Length); // offset to string table
w.WriteBytes(ma.ToArray());
w.WriteInt32(_StringTable.Count);
for (int i = 0; i < _StringTable.Count; i++)
{
w.WriteNullTerminatedString(_StringTable[i]);
}
}
private System.Collections.Specialized.StringCollection _StringTable = new System.Collections.Specialized.StringCollection();
private int MakeStringTableEntry(string value)
{
if (!_StringTable.Contains(value))
_StringTable.Add(value);
return _StringTable.IndexOf(value);
}
private object ReadObject(Reader r)
{
AutoSaveKnownType typeId = (AutoSaveKnownType) r.ReadInt32();
switch (typeId)
{
case AutoSaveKnownType.Null: return null;
case AutoSaveKnownType.Object:
{
int index = r.ReadInt32();
string typeName = _StringTable[index];
break;
}
}
return null;
}
private void WriteObject(Writer w, object o)
{
if (o == null)
{
w.WriteInt32((int)AutoSaveKnownType.Null); // null
return;
}
w.WriteInt32((int)AutoSaveKnownType.Object);
Type t = o.GetType();
w.WriteInt32(MakeStringTableEntry(t.FullName));
// public instance properties are really the only things we care about
System.Reflection.PropertyInfo[] pis = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
System.Collections.Generic.List<PropertyInfo> list = new System.Collections.Generic.List<PropertyInfo>();
for (int i = 0; i < pis.Length; i++)
{
if (pis[i].GetCustomAttribute<NonSerializedPropertyAttribute>() != null)
{
continue;
}
list.Add(pis[i]);
}
w.WriteInt32(list.Count);
for (int i = 0; i < list.Count; i++)
{
WriteProperty(w, list[i], o);
}
}
private void WriteProperty(Writer w, PropertyInfo propertyInfo, object obj)
{
w.WriteInt32(MakeStringTableEntry(propertyInfo.Name));
w.WriteInt32(MakeStringTableEntry(propertyInfo.PropertyType.FullName));
object val = propertyInfo.GetValue(obj);
if (val == obj)
return;
WriteValue(w, val);
}
private void WriteValue(Writer w, object val)
{
if (val is string)
{
w.WriteInt32((int)AutoSaveKnownType.String);
w.WriteInt32(MakeStringTableEntry(val as string));
}
else if (val is byte)
{
w.WriteInt32((int)AutoSaveKnownType.Byte);
w.WriteByte((byte)val);
}
else if (val is sbyte)
{
w.WriteInt32((int)AutoSaveKnownType.SByte);
w.WriteSByte((sbyte)val);
}
else if (val is char)
{
w.WriteInt32((int)AutoSaveKnownType.Char);
w.WriteChar((char)val);
}
else if (val is short)
{
w.WriteInt32((int)AutoSaveKnownType.Int16);
w.WriteInt16((short)val);
}
else if (val is int)
{
w.WriteInt32((int)AutoSaveKnownType.Int32);
w.WriteInt32((int)val);
}
else if (val is long)
{
w.WriteInt32((int)AutoSaveKnownType.Int64);
w.WriteInt64((long)val);
}
else if (val is ushort)
{
w.WriteInt32((int)AutoSaveKnownType.UInt16);
w.WriteUInt16((ushort)val);
}
else if (val is uint)
{
w.WriteInt32((int)AutoSaveKnownType.UInt32);
w.WriteUInt32((uint)val);
}
else if (val is ulong)
{
w.WriteInt32((int)AutoSaveKnownType.UInt64);
w.WriteUInt64((ulong)val);
}
else if (val is float)
{
w.WriteInt32((int)AutoSaveKnownType.Single);
w.WriteSingle((float)val);
}
else if (val is double)
{
w.WriteInt32((int)AutoSaveKnownType.Double);
w.WriteDouble((double)val);
}
else if (val is decimal)
{
w.WriteInt32((int)AutoSaveKnownType.Decimal);
w.WriteDecimal((decimal)val);
}
else if (val is Guid)
{
w.WriteInt32((int)AutoSaveKnownType.Guid);
w.WriteGuid((Guid)val);
}
else if (val is System.Collections.IList)
{
w.WriteInt32((int)AutoSaveKnownType.List);
System.Collections.IList il = (val as System.Collections.IList);
w.WriteInt32(il.Count);
for (int i = 0; i < il.Count; i++)
{
WriteValue(w, il[i]);
}
}
else
{
w.WriteInt32((int)AutoSaveKnownType.Object);
WriteObject(w, val);
}
}
}
}

View File

@ -0,0 +1,23 @@
namespace UniversalEditor.Plugins.AutoSave
{
public enum AutoSaveKnownType
{
Object = -1,
Null = 0,
String,
Char,
Byte,
SByte,
Int16,
Int32,
Int64,
UInt16,
UInt32,
UInt64,
Single,
Double,
Decimal,
Guid,
List
}
}

View File

@ -0,0 +1,39 @@
//
// AutoSaveObjectModel.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2021 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.Plugins.AutoSave
{
public class AutoSaveObjectModel : ObjectModel
{
public ObjectModel ObjectModel { get; set; } = null;
public string OriginalFileName { get; set; } = null;
public DateTime LastUpdateDateTime { get; set; } = DateTime.Now;
public override void Clear()
{
}
public override void CopyTo(ObjectModel where)
{
}
}
}

View File

@ -19,7 +19,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using MBS.Framework;
using MBS.Framework.UserInterface;
using UniversalEditor.Accessors;
using UniversalEditor.Plugins.AutoSave.Dialogs;
using UniversalEditor.UserInterface;
namespace UniversalEditor.Plugins.AutoSave
{
@ -27,19 +32,86 @@ namespace UniversalEditor.Plugins.AutoSave
{
private Timer tmr = new Timer();
private AutoSaveDataFormat asdf = new AutoSaveDataFormat();
private string GetAutosavePath()
{
return String.Format("/tmp/autosave/{0}", Application.Instance.ShortName);
}
private void tmr_Tick(object sender, EventArgs e)
{
Console.WriteLine("autosave: looking for dirty documents...");
IHostApplication ha = (Application.Instance as IHostApplication);
string path = System.IO.Path.Combine(new string[] { GetAutosavePath(), DateTime.Now.ToString("yyyyMMdd") });
Console.WriteLine("autosave: saving dirty documents in /tmp/autosave/universal-editor/...");
for (int i = 0; i < ha.CurrentWindow.Editors.Count; i++)
{
Editor ed = ha.CurrentWindow.Editors[i];
if (ed.Changed || !ed.Document.IsSaved)
{
string filename = System.IO.Path.Combine(new string[] { path, String.Format("{0}{1}.tmp", DateTime.Now.ToString("HHmmss"), i.ToString().PadLeft(2, '0')) });
string dir = System.IO.Path.GetDirectoryName(filename);
if (!System.IO.Directory.Exists(dir))
System.IO.Directory.CreateDirectory(dir);
if (!fas.ContainsKey(ed))
{
fas[ed] = new FileAccessor(filename, true, true);
}
AutoSaveObjectModel autosave = new AutoSaveObjectModel();
autosave.ObjectModel = ed.ObjectModel;
if (ed.Document.IsSaved)
{
autosave.OriginalFileName = ed.Document.Accessor.GetFileName();
}
else
{
autosave.OriginalFileName = null;
}
Document.Save(autosave, asdf, fas[ed]);
i++;
}
}
Console.WriteLine("autosave: going back to sleep");
}
private System.Collections.Generic.Dictionary<Editor, FileAccessor> fas = new System.Collections.Generic.Dictionary<Editor, FileAccessor>();
protected override void InitializeInternal()
{
base.InitializeInternal();
tmr.Duration = 5 /*minutes*/ * 60 /*seconds in a minute*/ * 1000 /*milliseconds in a second*/;
// check to see if we have any dirty documents
Console.WriteLine("autosave: checking for existing dirty documents...");
string path = GetAutosavePath();
if (!System.IO.Directory.Exists(path))
{
return;
}
string[] autosaves = System.IO.Directory.GetFiles(path, "*.tmp", System.IO.SearchOption.AllDirectories);
if (autosaves.Length > 0)
{
AutoSaveDialog dlg = new AutoSaveDialog();
dlg.FileNames.AddRange(autosaves);
if (dlg.ShowDialog() == DialogResult.OK)
{
}
}
tmr.Duration = 10000; // 5 /*minutes*/ * 60 /*seconds in a minute*/ * 1000 /*milliseconds in a second*/;
tmr.Tick += tmr_Tick;
tmr.Enabled = true;
}

View File

@ -0,0 +1,46 @@
using System;
using System.Reflection;
using MBS.Framework;
using MBS.Framework.Drawing;
using MBS.Framework.UserInterface;
using MBS.Framework.UserInterface.Controls;
using MBS.Framework.UserInterface.Controls.ListView;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
namespace UniversalEditor.Plugins.AutoSave.Dialogs
{
[ContainerLayout(typeof(AutoSaveDialog), "UniversalEditor.Plugins.AutoSave.Dialogs.AutoSaveDialog.glade")]
public class AutoSaveDialog : CustomDialog
{
private Label lblPrompt;
private ListViewControl lv;
public System.Collections.Specialized.StringCollection FileNames { get; } = new System.Collections.Specialized.StringCollection();
protected override void OnCreated(EventArgs e)
{
base.OnCreated(e);
lblPrompt.Text = lblPrompt.Text.Replace("${Application.Title}", Application.Instance.Title);
Document[] ds = new Document[FileNames.Count];
for (int i = 0; i < ds.Length; i++)
{
ds[i] = new Document(new AutoSaveObjectModel(), new AutoSaveDataFormat(), new FileAccessor(FileNames[i], false, false, true));
ds[i].Load();
string fn = (ds[i].ObjectModel as AutoSaveObjectModel).OriginalFileName;
fn = String.IsNullOrEmpty(fn) ? "(untitled)" : fn;
string dts = String.Format("{0} {1}", (ds[i].ObjectModel as AutoSaveObjectModel).LastUpdateDateTime.ToLongDateString(), (ds[i].ObjectModel as AutoSaveObjectModel).LastUpdateDateTime.ToLongTimeString());
lv.Model.Rows.Add(new TreeModelRow(new TreeModelRowColumn[]
{
new TreeModelRowColumn(lv.Model.Columns[0], fn),
new TreeModelRowColumn(lv.Model.Columns[1], dts)
}));
}
}
}
}

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkTreeStore" id="tmFiles">
<columns>
<!-- column-name colFileFileName -->
<column type="gchararray"/>
<!-- column-name colFileLastModificationDateTime -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkDialog">
<property name="can_focus">False</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<property name="type_hint">dialog</property>
<child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cmdOK">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cmdCancel">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">16</property>
<property name="margin_right">16</property>
<property name="margin_top">16</property>
<property name="margin_bottom">16</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">16</property>
<property name="stock">gtk-dialog-info</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lblPrompt">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">${Application.Title} has recovered the following files. Save the ones you wish to keep.</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="lv">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">tmFiles</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="chFileFileName">
<property name="resizable">True</property>
<property name="title" translatable="yes">File name</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="chFileLastModificationDateTime">
<property name="resizable">True</property>
<property name="title" translatable="yes">Last modified</property>
<property name="clickable">True</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@ -33,6 +33,10 @@
<ItemGroup>
<Compile Include="AutoSavePlugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="AutoSaveDataFormat.cs" />
<Compile Include="AutoSaveKnownType.cs" />
<Compile Include="Dialogs\AutoSaveDialog.cs" />
<Compile Include="AutoSaveObjectModel.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\MBS.Framework\MBS.Framework\MBS.Framework.csproj">
@ -43,6 +47,20 @@
<Project>{29E1C1BB-3EA5-4062-B62F-85EEC703FE07}</Project>
<Name>MBS.Framework.UserInterface</Name>
</ProjectReference>
<ProjectReference Include="..\..\Libraries\UniversalEditor.UserInterface\UniversalEditor.UserInterface.csproj">
<Project>{8622EBC4-8E20-476E-B284-33D472081F5C}</Project>
<Name>UniversalEditor.UserInterface</Name>
</ProjectReference>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
<Project>{2D4737E6-6D95-408A-90DB-8DFF38147E85}</Project>
<Name>UniversalEditor.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Dialogs\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Dialogs\AutoSaveDialog.glade" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>