43
43
tags = new Dictionary<string, Tag> ();
45
45
create_date = DateTime.MinValue;
46
46
change_date = DateTime.MinValue;
54
56
public string Title
57
set { title = value; }
66
76
public DateTime CreateDate
68
get { return create_date; }
69
set { create_date = value; }
72
86
public DateTime ChangeDate
74
get { return change_date; }
75
set { change_date = value; }
78
96
// FIXME: the next five attributes don't belong here (the data
82
100
public int CursorPosition
84
get { return cursor_pos; }
85
set { cursor_pos = value; }
91
set { width = value; }
96
get { return height; }
97
set { height = value; }
112
150
public Dictionary<string, Tag> Tags
117
157
public bool IsOpenOnStartup
119
get { return open_on_startup; }
120
set { open_on_startup = value; }
160
return open_on_startup;
163
open_on_startup = value;
123
167
public void SetPositionExtent (int x, int y, int width, int height)
125
169
Debug.Assert (x >= 0 && y >= 0);
301
350
this.data = new NoteDataBufferSynchronizer (data);
302
351
this.filepath = filepath;
303
352
this.manager = manager;
305
354
// Make sure each of the tags that NoteData found point to the
306
355
// instance of this note.
307
356
foreach (Tag tag in data.Tags.Values) {
311
360
save_timeout = new InterruptableTimeout ();
312
361
save_timeout.Timeout += SaveTimeout;
314
363
childWidgetQueue = new Queue <ChildWidgetData> ();
317
368
static string UrlFromPath (string filepath)
319
370
return "note://tomboy/" +
320
Path.GetFileNameWithoutExtension (filepath);
371
Path.GetFileNameWithoutExtension (filepath);
323
374
public static Note CreateNewNote (string title,
327
378
NoteData data = new NoteData (UrlFromPath (filepath));
328
379
data.Title = title;
426
// Prevent any other condition forcing a save on the note
427
// if Delete has been called.
374
431
// Do nothing if we don't need to save. Avoids unneccessary saves
375
432
// e.g on forced quit when we call save for every note.
376
433
if (!save_needed)
440
497
window.GetPosition (out cur_x, out cur_y);
441
498
window.GetSize (out cur_width, out cur_height);
443
if (data.Data.X == cur_x &&
444
data.Data.Y == cur_y &&
445
data.Data.Width == cur_width &&
446
data.Data.Height == cur_height)
500
if (data.Data.X == cur_x &&
501
data.Data.Y == cur_y &&
502
data.Data.Width == cur_width &&
503
data.Data.Height == cur_height)
449
506
data.Data.SetPositionExtent (cur_x, cur_y, cur_width, cur_height);
451
508
DebugSave ("WindowConfigureEvent queueing save");
452
509
QueueSave (false);
455
512
[GLib.ConnectBefore]
456
void WindowDestroyed (object sender, EventArgs args)
513
void WindowDestroyed (object sender, EventArgs args)
491
548
Logger.Log ("Error while saving: {0}", e);
495
552
public void AddTag (Tag tag)
498
555
throw new ArgumentNullException ("Note.AddTag () called with a null tag.");
500
557
tag.AddNote (this);
502
559
if (!data.Data.Tags.ContainsKey (tag.NormalizedName)) {
503
560
data.Data.Tags [tag.NormalizedName] = tag;
509
566
QueueSave (true);
513
570
public void RemoveTag (Tag tag)
516
573
throw new ArgumentException ("Note.RemoveTag () called with a null tag.");
518
575
if (!data.Data.Tags.ContainsKey (tag.NormalizedName))
521
578
if (TagRemoving != null)
522
579
TagRemoving (this, tag);
524
581
data.Data.Tags.Remove (tag.NormalizedName);
525
582
tag.RemoveNote (this);
527
584
if (TagRemoved != null)
528
585
TagRemoved (this, tag.NormalizedName);
530
587
DebugSave ("Tag removed, queueing save");
531
588
QueueSave (true);
591
public bool ContainsTag (Tag tag)
593
if (data.Data.Tags.ContainsKey (tag.NormalizedName) == true)
534
599
public void AddChildWidget (Gtk.TextChildAnchor childAnchor, Gtk.Widget widget)
560
625
public string Uri
562
get { return data.Data.Uri; }
628
return data.Data.Uri;
567
get { return data.Data.Uri.Replace ("note://tomboy/",""); }// TODO: Store on Note instantiation
570
public string FilePath
572
get { return filepath; }
573
set { filepath = value; }
578
get { return data.Data.Title; }
635
return data.Data.Uri.Replace ("note://tomboy/",""); // TODO: Store on Note instantiation
639
public string FilePath
652
return data.Data.Title;
580
655
if (data.Data.Title != value) {
581
656
if (window != null)
587
662
if (Renamed != null)
588
663
Renamed (this, old_title);
590
665
QueueSave (true); // TODO: Right place for this?
595
670
public void RenameWithoutLinkUpdate (string newTitle)
597
672
if (data.Data.Title != newTitle) {
598
673
if (window != null)
599
674
window.Title = newTitle;
601
676
data.Data.Title = newTitle;
604
679
if (Renamed != null)
605
680
Renamed (this, newTitle);
607
682
QueueSave (true); // TODO: Right place for this?
611
public string XmlContent
686
public string XmlContent
613
get { return data.Text; }
615
692
if (buffer != null) {
616
693
buffer.SetText("");
617
694
NoteBufferArchiver.Deserialize (buffer, value);
624
701
/// Return the complete contents of this note's .note XML file
625
702
/// In case of any error, null is returned.
662
739
// This will throw an XmlException if foreignNoteXml is not parseable
663
740
xmlDoc.LoadXml (foreignNoteXml);
666
743
StringReader reader = new StringReader (foreignNoteXml);
667
744
XmlTextReader xml = new XmlTextReader (reader);
668
745
xml.Namespaces = false;
670
747
// Remove tags now, since a note with no tags has
671
748
// no "tags" element in the XML
672
749
foreach (Tag tag in Tags)
675
752
while (xml.Read ()) {
676
753
switch (xml.NodeType) {
683
760
XmlContent = xml.ReadInnerXml ();
685
762
case "last-change-date":
686
data.Data.ChangeDate =
687
XmlConvert.ToDateTime (xml.ReadString (), NoteArchiver.DATE_TIME_FORMAT);
763
data.Data.ChangeDate =
764
XmlConvert.ToDateTime (xml.ReadString (), NoteArchiver.DATE_TIME_FORMAT);
689
766
case "create-date":
690
data.Data.CreateDate =
691
XmlConvert.ToDateTime (xml.ReadString (), NoteArchiver.DATE_TIME_FORMAT);
767
data.Data.CreateDate =
768
XmlConvert.ToDateTime (xml.ReadString (), NoteArchiver.DATE_TIME_FORMAT);
694
771
XmlDocument doc = new XmlDocument ();
711
788
// TODO: Any reason to queue a save here? Maybe not for sync but for others?
714
791
// TODO: CODE DUPLICATION SUCKS
715
792
List<string> ParseTags (XmlNode tagNodes)
717
794
List<string> tags = new List<string> ();
719
796
foreach (XmlNode node in tagNodes.SelectNodes ("//tag")) {
720
797
string tag = node.InnerText;
730
807
if (buffer != null)
731
return buffer.GetSlice (buffer.StartIter,
733
false /* hidden_chars */);
808
return buffer.GetSlice (buffer.StartIter,
810
false /* hidden_chars */);
735
812
return XmlDecoder.Decode (XmlContent);
741
818
Logger.Log ("Setting text content for closed notes not supported");
746
823
public NoteData Data
748
get { return data.GetDataSynchronized (); }
751
public DateTime CreateDate
753
get { return data.Data.CreateDate; }
756
public DateTime ChangeDate
758
get { return data.Data.ChangeDate; }
826
return data.GetDataSynchronized ();
830
public DateTime CreateDate
833
return data.Data.CreateDate;
837
public DateTime ChangeDate
840
return data.Data.ChangeDate;
761
844
public NoteManager Manager
763
get { return manager; }
764
set { manager = value; }
767
854
public NoteTagTable TagTable
770
857
if (tag_table == null) {
772
859
// NOTE: Sharing the same TagTable means
773
860
// that formatting is duplicated between
775
862
tag_table = NoteTagTable.Instance;
777
864
// NOTE: GtkSpell chokes on shared
778
865
// TagTables because it blindly tries to
779
866
// create a new "gtkspell-misspelling"
780
867
// tag, which fails if one already
781
868
// exists in the table.
782
869
tag_table = new NoteTagTable ();
785
872
return tag_table;
789
876
public bool HasBuffer
791
get { return null != buffer; }
879
return null != buffer;
794
883
public NoteBuffer Buffer
797
886
if (buffer == null) {
798
Logger.Log ("Creating Buffer for '{0}'...",
887
Logger.Log ("Creating Buffer for '{0}'...",
801
890
buffer = new NoteBuffer (TagTable, this);
802
891
data.Buffer = buffer;
814
903
public bool HasWindow
816
get { return null != window; }
906
return null != window;
819
public NoteWindow Window
910
public NoteWindow Window
822
913
if (window == null) {
823
914
window = new NoteWindow (this);
824
915
window.Destroyed += WindowDestroyed;
825
916
window.ConfigureEvent += WindowConfigureEvent;
827
918
if (data.Data.HasExtent ())
828
window.SetDefaultSize (data.Data.Width,
919
window.SetDefaultSize (data.Data.Width,
831
922
if (data.Data.HasPosition ())
832
923
window.Move (data.Data.X, data.Data.Y);
840
931
// the window is showing.
841
932
ProcessChildWidgetQueue ();
847
public bool IsSpecial
849
get { return NoteManager.StartNoteUri == data.Data.Uri; }
938
public bool IsSpecial
941
return NoteManager.StartNoteUri == data.Data.Uri;
855
948
// Note is new if created in the last 24 hours.
856
949
return data.Data.CreateDate > DateTime.Now.AddHours (-24);
862
get { return buffer != null; }
956
return buffer != null;
867
get { return window != null; }
963
return window != null;
870
967
public bool IsPinned
873
970
string pinned_uris = (string)
874
Preferences.Get (Preferences.MENU_PINNED_NOTES);
971
Preferences.Get (Preferences.MENU_PINNED_NOTES);
875
972
return pinned_uris.IndexOf (Uri) > -1;
878
975
string new_pinned = "";
879
976
string old_pinned = (string)
880
Preferences.Get (Preferences.MENU_PINNED_NOTES);
977
Preferences.Get (Preferences.MENU_PINNED_NOTES);
881
978
bool pinned = old_pinned.IndexOf (Uri) > -1;
897
994
Preferences.Set (Preferences.MENU_PINNED_NOTES, new_pinned);
901
998
public bool IsOpenOnStartup
903
get { return Data.IsOpenOnStartup; }
1001
return Data.IsOpenOnStartup;
905
1004
if (Data.IsOpenOnStartup != value) {
906
1005
Data.IsOpenOnStartup = value;
962
1063
return Instance.ReadFile (read_file, uri);
965
public virtual NoteData ReadFile (string read_file, string uri)
1066
public virtual NoteData ReadFile (string read_file, string uri)
967
1068
NoteData note = new NoteData (uri);
968
1069
string version = "";
970
StreamReader reader = new StreamReader (read_file,
971
System.Text.Encoding.UTF8);
1071
StreamReader reader = new StreamReader (read_file,
1072
System.Text.Encoding.UTF8);
972
1073
XmlTextReader xml = new XmlTextReader (reader);
973
1074
xml.Namespaces = false;
988
1089
note.Text = xml.ReadInnerXml ();
990
1091
case "last-change-date":
992
XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
1093
XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
994
1095
case "create-date":
996
XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
1097
XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
998
1099
case "cursor-position":
999
1100
note.CursorPosition = int.Parse (xml.ReadString ());
1043
1144
Instance.WriteFile (write_file, note);
1046
public virtual void WriteFile (string write_file, NoteData note)
1147
public virtual void WriteFile (string write_file, NoteData note)
1048
1149
string tmp_file = write_file + ".tmp";
1089
1190
xml.WriteStartDocument ();
1090
1191
xml.WriteStartElement (null, "note", "http://beatniksoftware.com/tomboy");
1091
xml.WriteAttributeString(null,
1095
xml.WriteAttributeString("xmlns",
1098
"http://beatniksoftware.com/tomboy/link");
1099
xml.WriteAttributeString("xmlns",
1102
"http://beatniksoftware.com/tomboy/size");
1192
xml.WriteAttributeString(null,
1196
xml.WriteAttributeString("xmlns",
1199
"http://beatniksoftware.com/tomboy/link");
1200
xml.WriteAttributeString("xmlns",
1203
"http://beatniksoftware.com/tomboy/size");
1104
1205
xml.WriteStartElement (null, "title", null);
1105
1206
xml.WriteString (note.Title);
1114
1215
xml.WriteStartElement (null, "last-change-date", null);
1115
1216
xml.WriteString (
1116
XmlConvert.ToString (note.ChangeDate, DATE_TIME_FORMAT));
1217
XmlConvert.ToString (note.ChangeDate, DATE_TIME_FORMAT));
1117
1218
xml.WriteEndElement ();
1119
1220
if (note.CreateDate != DateTime.MinValue) {
1120
1221
xml.WriteStartElement (null, "create-date", null);
1121
1222
xml.WriteString (
1122
XmlConvert.ToString (note.CreateDate, DATE_TIME_FORMAT));
1223
XmlConvert.ToString (note.CreateDate, DATE_TIME_FORMAT));
1123
1224
xml.WriteEndElement ();
1142
1243
xml.WriteStartElement (null, "y", null);
1143
1244
xml.WriteString (note.Y.ToString ());
1144
1245
xml.WriteEndElement ();
1146
1247
if (note.Tags.Count > 0) {
1147
1248
xml.WriteStartElement (null, "tags", null);
1148
1249
foreach (Tag tag in note.Tags.Values) {
1160
1261
xml.WriteEndElement (); // Note
1161
1262
xml.WriteEndDocument ();
1165
1266
// Parse the tags from the <tags> element
1167
1268
List<string> ParseTags (XmlNode tagNodes)
1169
1270
List<string> tags = new List<string> ();
1171
1272
foreach (XmlNode node in tagNodes.SelectNodes ("//tag")) {
1172
1273
string tag = node.InnerText;
1173
1274
tags.Add (tag);
1179
1280
public virtual string GetRenamedNoteXml (string noteXml, string oldTitle, string newTitle)
1181
1282
string updatedXml;
1183
1284
// Replace occurences of oldTitle with newTitle in noteXml
1184
1285
string titleTagPattern =
1185
string.Format ("<title>{0}</title>", oldTitle);
1286
string.Format ("<title>{0}</title>", oldTitle);
1186
1287
string titleTagReplacement =
1187
string.Format ("<title>{0}</title>", newTitle);
1288
string.Format ("<title>{0}</title>", newTitle);
1188
1289
updatedXml = Regex.Replace (noteXml, titleTagPattern, titleTagReplacement);
1190
1291
string titleContentPattern =
1191
string.Format ("<note-content([^>]*)>\\s*{0}", oldTitle);
1292
string.Format ("<note-content([^>]*)>\\s*{0}", oldTitle);
1192
1293
string titleContentReplacement =
1193
string.Format ("<note-content$1>{0}", newTitle);
1294
string.Format ("<note-content$1>{0}", newTitle);
1194
1295
updatedXml = Regex.Replace (updatedXml, titleContentPattern, titleContentReplacement);
1196
1297
return updatedXml;
1199
1300
public virtual string GetTitleFromNoteXml (string noteXml)
1201
1302
if (noteXml != null && noteXml.Length > 0) {
1206
1307
switch (xml.NodeType) {
1207
1308
case XmlNodeType.Element:
1208
1309
switch (xml.Name) {
1210
return xml.ReadString ();
1311
return xml.ReadString ();
1222
1323
public class NoteUtils
1224
public static void ShowDeletionDialog (Note note, Gtk.Window parent)
1325
public static void ShowDeletionDialog (List<Note> notes, Gtk.Window parent)
1226
HIGMessageDialog dialog =
1227
new HIGMessageDialog (
1229
Gtk.DialogFlags.DestroyWithParent,
1230
Gtk.MessageType.Question,
1231
Gtk.ButtonsType.None,
1232
Catalog.GetString ("Really delete this note?"),
1233
Catalog.GetString ("If you delete a note it is " +
1234
"permanently lost."));
1329
if (notes.Count == 1)
1330
message = Catalog.GetString ("Really delete this note?");
1332
message = Catalog.GetString ("Really delete these notes?");
1334
HIGMessageDialog dialog =
1335
new HIGMessageDialog (
1337
Gtk.DialogFlags.DestroyWithParent,
1338
Gtk.MessageType.Question,
1339
Gtk.ButtonsType.None,
1341
Catalog.GetString ("If you delete a note it is " +
1342
"permanently lost."));
1236
1344
Gtk.Button button;