~ted/ubuntu/lucid/tomboy/with-patch

« back to all changes in this revision

Viewing changes to Tomboy/Note.cs

  • Committer: Bazaar Package Importer
  • Author(s): Pedro Fragoso
  • Date: 2008-01-15 11:32:52 UTC
  • mfrom: (1.1.31 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20080115113252-p59wg7nqkl6vcg7a
Tags: 0.9.4-0ubuntu1
* New upstream release (LP: #181798)
  - Fix crash during note deletion 
  - Fix null reference exception 
  - Fix mnemonics in sync preferences dialog 
  - Fix fuse mount timeout for sync 
  - New port option for SSH sync 
  - New multi-select notes support in Search All Notes window
  - New config dialog for Insert Timestamp Add-in 
  - New gconf preference, middle-click paste on Tomboy icon
  - New gconf preference, disable ESC closing notes 
  - New paragraph within a bullet with SHIFT + ENTER
  - New bug numbers as links in Export to HTML 
  - New notebook notes can be created off notebook's context menu.
  - New sketching add-in (still incomplete, --enable-sketching)
  - New "Unfiled Notes" item to notebook list 
  - New drag note to "Unfiled Notes" to remove from notebook 
 * debian/tomboy.menu: updated

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
                int width, height;
29
29
                int x, y;
30
30
                bool open_on_startup;
31
 
                
 
31
 
32
32
                Dictionary<string, Tag> tags;
33
33
 
34
34
                const int noPosition = -1;
39
39
                        this.text = "";
40
40
                        x = noPosition;
41
41
                        y = noPosition;
42
 
                        
 
42
 
43
43
                        tags = new Dictionary<string, Tag> ();
44
 
                        
 
44
 
45
45
                        create_date = DateTime.MinValue;
46
46
                        change_date = DateTime.MinValue;
47
47
                }
48
48
 
49
49
                public string Uri
50
50
                {
51
 
                        get { return uri; }
 
51
                        get {
 
52
                                return uri;
 
53
                        }
52
54
                }
53
55
 
54
56
                public string Title
55
57
                {
56
 
                        get { return title; }
57
 
                        set { title = value; }
 
58
                        get {
 
59
                                return title;
 
60
                        }
 
61
                        set {
 
62
                                title = value;
 
63
                        }
58
64
                }
59
65
 
60
66
                public string Text
61
67
                {
62
 
                        get { return text; }
63
 
                        set { text = value; }
 
68
                        get {
 
69
                                return text;
 
70
                        }
 
71
                        set {
 
72
                                text = value;
 
73
                        }
64
74
                }
65
75
 
66
76
                public DateTime CreateDate
67
77
                {
68
 
                        get { return create_date; }
69
 
                        set { create_date = value; }
 
78
                        get {
 
79
                                return create_date;
 
80
                        }
 
81
                        set {
 
82
                                create_date = value;
 
83
                        }
70
84
                }
71
85
 
72
86
                public DateTime ChangeDate
73
87
                {
74
 
                        get { return change_date; }
75
 
                        set { change_date = value; }
 
88
                        get {
 
89
                                return change_date;
 
90
                        }
 
91
                        set {
 
92
                                change_date = value;
 
93
                        }
76
94
                }
77
95
 
78
96
                // FIXME: the next five attributes don't belong here (the data
81
99
 
82
100
                public int CursorPosition
83
101
                {
84
 
                        get { return cursor_pos; }
85
 
                        set { cursor_pos = value; }
 
102
                        get {
 
103
                                return cursor_pos;
 
104
                        }
 
105
                        set {
 
106
                                cursor_pos = value;
 
107
                        }
86
108
                }
87
109
 
88
110
                public int Width
89
111
                {
90
 
                        get { return width; }
91
 
                        set { width = value; }
 
112
                        get {
 
113
                                return width;
 
114
                        }
 
115
                        set {
 
116
                                width = value;
 
117
                        }
92
118
                }
93
119
 
94
120
                public int Height
95
121
                {
96
 
                        get { return height; }
97
 
                        set { height = value; }
 
122
                        get {
 
123
                                return height;
 
124
                        }
 
125
                        set {
 
126
                                height = value;
 
127
                        }
98
128
                }
99
129
 
100
130
                public int X
101
131
                {
102
 
                        get { return x; }
103
 
                        set { x = value; }
 
132
                        get {
 
133
                                return x;
 
134
                        }
 
135
                        set {
 
136
                                x = value;
 
137
                        }
104
138
                }
105
139
 
106
140
                public int Y
107
141
                {
108
 
                        get { return y; }
109
 
                        set { y = value; }
 
142
                        get {
 
143
                                return y;
 
144
                        }
 
145
                        set {
 
146
                                y = value;
 
147
                        }
110
148
                }
111
 
                
 
149
 
112
150
                public Dictionary<string, Tag> Tags
113
151
                {
114
 
                        get { return tags; }
 
152
                        get {
 
153
                                return tags;
 
154
                        }
115
155
                }
116
 
                
 
156
 
117
157
                public bool IsOpenOnStartup
118
158
                {
119
 
                        get { return open_on_startup; }
120
 
                        set { open_on_startup = value; }
 
159
                        get {
 
160
                                return open_on_startup;
 
161
                        }
 
162
                        set {
 
163
                                open_on_startup = value;
 
164
                        }
121
165
                }
122
 
                
 
166
 
123
167
                public void SetPositionExtent (int x, int y, int width, int height)
124
168
                {
125
169
                        Debug.Assert (x >= 0 && y >= 0);
166
210
 
167
211
                public NoteData Data
168
212
                {
169
 
                        get { return data; }
 
213
                        get {
 
214
                                return data;
 
215
                        }
170
216
                }
171
217
 
172
218
                public NoteBuffer Buffer
173
219
                {
174
 
                        get { return buffer; }
 
220
                        get {
 
221
                                return buffer;
 
222
                        }
175
223
                        set {
176
224
                                buffer = value;
177
225
                                buffer.Changed += BufferChanged;
212
260
                void SynchronizeText ()
213
261
                {
214
262
                        if (TextInvalid () && buffer != null) {
215
 
                                data.Text = NoteBufferArchiver.Serialize (buffer); 
 
263
                                data.Text = NoteBufferArchiver.Serialize (buffer);
216
264
                        }
217
265
                }
218
266
 
225
273
                                buffer.Clear ();
226
274
 
227
275
                                // Load the stored xml text
228
 
                                NoteBufferArchiver.Deserialize (buffer, 
229
 
                                                                buffer.StartIter, 
230
 
                                                                data.Text);
 
276
                                NoteBufferArchiver.Deserialize (buffer,
 
277
                                                                buffer.StartIter,
 
278
                                                                data.Text);
231
279
                                buffer.Modified = false;
232
280
 
233
281
                                Gtk.TextIter cursor;
267
315
                }
268
316
        }
269
317
 
270
 
        public class Note 
 
318
        public class Note
271
319
        {
272
320
                readonly NoteDataBufferSynchronizer data;
273
321
 
274
322
                string filepath;
275
323
 
276
324
                bool save_needed;
 
325
                bool is_deleting;
277
326
 
278
327
                NoteManager manager;
279
328
                NoteWindow window;
301
350
                        this.data = new NoteDataBufferSynchronizer (data);
302
351
                        this.filepath = filepath;
303
352
                        this.manager = manager;
304
 
                        
 
353
 
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) {
308
357
                                AddTag (tag);
309
358
                        }
310
 
                        
 
359
 
311
360
                        save_timeout = new InterruptableTimeout ();
312
361
                        save_timeout.Timeout += SaveTimeout;
313
362
 
314
363
                        childWidgetQueue = new Queue <ChildWidgetData> ();
 
364
                        
 
365
                        is_deleting = false;
315
366
                }
316
367
 
317
368
                static string UrlFromPath (string filepath)
318
369
                {
319
370
                        return "note://tomboy/" +
320
 
                                Path.GetFileNameWithoutExtension (filepath);
 
371
                               Path.GetFileNameWithoutExtension (filepath);
321
372
                }
322
373
 
323
374
                public static Note CreateNewNote (string title,
324
 
                                                  string filepath,
325
 
                                                  NoteManager manager)
 
375
                                                  string filepath,
 
376
                                                  NoteManager manager)
326
377
                {
327
378
                        NoteData data = new NoteData (UrlFromPath (filepath));
328
379
                        data.Title = title;
332
383
                }
333
384
 
334
385
                public static Note CreateExistingNote (NoteData data,
335
 
                                                       string filepath,
336
 
                                                       NoteManager manager)
 
386
                                                       string filepath,
 
387
                                                       NoteManager manager)
337
388
                {
338
389
                        if (data.CreateDate == DateTime.MinValue)
339
390
                                data.CreateDate = File.GetCreationTime (filepath);
344
395
 
345
396
                public void Delete ()
346
397
                {
 
398
                        is_deleting = true;
347
399
                        save_timeout.Cancel ();
348
 
                        
 
400
 
349
401
                        // Remove the note from all the tags
350
402
                        foreach (Tag tag in Tags) {
351
403
                                RemoveTag (tag);
355
407
                                window.Hide ();
356
408
                                window.Destroy ();
357
409
                        }
358
 
                        
 
410
 
359
411
                        // Remove note URI from GConf entry menu_pinned_notes
360
412
                        IsPinned = false;
361
413
                }
369
421
                        return note;
370
422
                }
371
423
 
372
 
                public void Save () 
 
424
                public void Save ()
373
425
                {
 
426
                        // Prevent any other condition forcing a save on the note
 
427
                        // if Delete has been called.
 
428
                        if (is_deleting)
 
429
                                return;
 
430
                        
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)
379
436
                        Logger.Log ("Saving '{0}'...", data.Data.Title);
380
437
 
381
438
                        NoteArchiver.Write (filepath, data.GetDataSynchronized ());
382
 
                        
 
439
 
383
440
                        if (Saved != null)
384
441
                                Saved (this);
385
442
                }
440
497
                        window.GetPosition (out cur_x, out cur_y);
441
498
                        window.GetSize (out cur_width, out cur_height);
442
499
 
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)
447
504
                                return;
448
505
 
449
506
                        data.Data.SetPositionExtent (cur_x, cur_y, cur_width, cur_height);
450
 
                        
 
507
 
451
508
                        DebugSave ("WindowConfigureEvent queueing save");
452
509
                        QueueSave (false);
453
510
                }
454
511
 
455
512
                [GLib.ConnectBefore]
456
 
                void WindowDestroyed (object sender, EventArgs args) 
 
513
                void WindowDestroyed (object sender, EventArgs args)
457
514
                {
458
515
                        window = null;
459
516
                }
491
548
                                Logger.Log ("Error while saving: {0}", e);
492
549
                        }
493
550
                }
494
 
                
 
551
 
495
552
                public void AddTag (Tag tag)
496
553
                {
497
554
                        if (tag == null)
498
555
                                throw new ArgumentNullException ("Note.AddTag () called with a null tag.");
499
556
 
500
557
                        tag.AddNote (this);
501
 
                        
 
558
 
502
559
                        if (!data.Data.Tags.ContainsKey (tag.NormalizedName)) {
503
560
                                data.Data.Tags [tag.NormalizedName] = tag;
504
561
 
509
566
                                QueueSave (true);
510
567
                        }
511
568
                }
512
 
                
 
569
 
513
570
                public void RemoveTag (Tag tag)
514
571
                {
515
572
                        if (tag == null)
516
573
                                throw new ArgumentException ("Note.RemoveTag () called with a null tag.");
517
 
                        
 
574
 
518
575
                        if (!data.Data.Tags.ContainsKey (tag.NormalizedName))
519
576
                                return;
520
 
                        
 
577
 
521
578
                        if (TagRemoving != null)
522
579
                                TagRemoving (this, tag);
523
 
                        
 
580
 
524
581
                        data.Data.Tags.Remove (tag.NormalizedName);
525
582
                        tag.RemoveNote (this);
526
 
                        
 
583
 
527
584
                        if (TagRemoved != null)
528
585
                                TagRemoved (this, tag.NormalizedName);
529
586
 
530
587
                        DebugSave ("Tag removed, queueing save");
531
588
                        QueueSave (true);
532
589
                }
 
590
                
 
591
                public bool ContainsTag (Tag tag)
 
592
                {
 
593
                        if (data.Data.Tags.ContainsKey (tag.NormalizedName) == true)
 
594
                                return true;
 
595
                        
 
596
                        return false;
 
597
                }
533
598
 
534
599
                public void AddChildWidget (Gtk.TextChildAnchor childAnchor, Gtk.Widget widget)
535
600
                {
559
624
 
560
625
                public string Uri
561
626
                {
562
 
                        get { return data.Data.Uri; }
 
627
                        get {
 
628
                                return data.Data.Uri;
 
629
                        }
563
630
                }
564
 
                
 
631
 
565
632
                public string Id
566
633
                {
567
 
                        get { return data.Data.Uri.Replace ("note://tomboy/",""); }// TODO: Store on Note instantiation
568
 
                }
569
 
 
570
 
                public string FilePath 
571
 
                {
572
 
                        get { return filepath; }
573
 
                        set { filepath = value; }
574
 
                }
575
 
 
576
 
                public string Title 
577
 
                {
578
 
                        get { return data.Data.Title; }
 
634
                        get {
 
635
                                return data.Data.Uri.Replace ("note://tomboy/","");        // TODO: Store on Note instantiation
 
636
                        }
 
637
                }
 
638
 
 
639
                public string FilePath
 
640
                {
 
641
                        get {
 
642
                                return filepath;
 
643
                        }
 
644
                        set {
 
645
                                filepath = value;
 
646
                        }
 
647
                }
 
648
 
 
649
                public string Title
 
650
                {
 
651
                        get {
 
652
                                return data.Data.Title;
 
653
                        }
579
654
                        set {
580
655
                                if (data.Data.Title != value) {
581
656
                                        if (window != null)
586
661
 
587
662
                                        if (Renamed != null)
588
663
                                                Renamed (this, old_title);
589
 
                                        
 
664
 
590
665
                                        QueueSave (true); // TODO: Right place for this?
591
666
                                }
592
667
                        }
593
668
                }
594
 
                
 
669
 
595
670
                public void RenameWithoutLinkUpdate (string newTitle)
596
671
                {
597
672
                        if (data.Data.Title != newTitle) {
598
673
                                if (window != null)
599
674
                                        window.Title = newTitle;
600
 
                                
 
675
 
601
676
                                data.Data.Title = newTitle;
602
 
                                
603
 
                                // HACK: 
 
677
 
 
678
                                // HACK:
604
679
                                if (Renamed != null)
605
680
                                        Renamed (this, newTitle);
606
 
                                
 
681
 
607
682
                                QueueSave (true); // TODO: Right place for this?
608
683
                        }
609
684
                }
610
685
 
611
 
                public string XmlContent 
 
686
                public string XmlContent
612
687
                {
613
 
                        get { return data.Text; }
614
 
                        set { 
 
688
                        get {
 
689
                                return data.Text;
 
690
                        }
 
691
                        set {
615
692
                                if (buffer != null) {
616
693
                                        buffer.SetText("");
617
694
                                        NoteBufferArchiver.Deserialize (buffer, value);
618
695
                                } else
619
 
                                        data.Text = value; 
 
696
                                        data.Text = value;
620
697
                        }
621
698
                }
622
 
                
 
699
 
623
700
                /// <summary>
624
701
                /// Return the complete contents of this note's .note XML file
625
702
                /// In case of any error, null is returned.
628
705
                {
629
706
                        if (!File.Exists (filepath))
630
707
                                return null;
631
 
                        
 
708
 
632
709
                        // Make sure file contents are up to date
633
710
                        save_needed = true; // HACK: Catches newly created notes
634
711
                        Save ();
646
723
                                        reader.Close ();
647
724
                        }
648
725
                }
649
 
                
 
726
 
650
727
                // Reload note data from a complete note XML string
651
728
                // Should referesh note window, too
652
729
                public void LoadForeignNoteXml (string foreignNoteXml)
662
739
                        // This will throw an XmlException if foreignNoteXml is not parseable
663
740
                        xmlDoc.LoadXml (foreignNoteXml);
664
741
                        xmlDoc = null;
665
 
                        
 
742
 
666
743
                        StringReader reader = new StringReader (foreignNoteXml);
667
744
                        XmlTextReader xml = new XmlTextReader (reader);
668
745
                        xml.Namespaces = false;
669
 
                        
 
746
 
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)
673
 
                                RemoveTag (tag);
 
750
                        RemoveTag (tag);
674
751
 
675
752
                        while (xml.Read ()) {
676
753
                                switch (xml.NodeType) {
683
760
                                                XmlContent = xml.ReadInnerXml ();
684
761
                                                break;
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);
688
765
                                                break;
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);
692
769
                                                break;
693
770
                                        case "tags":
694
771
                                                XmlDocument doc = new XmlDocument ();
707
784
                        }
708
785
 
709
786
                        xml.Close ();
710
 
                        
 
787
 
711
788
                        // TODO: Any reason to queue a save here?  Maybe not for sync but for others?
712
789
                }
713
 
                
 
790
 
714
791
                // TODO: CODE DUPLICATION SUCKS
715
792
                List<string> ParseTags (XmlNode tagNodes)
716
793
                {
717
794
                        List<string> tags = new List<string> ();
718
 
                        
 
795
 
719
796
                        foreach (XmlNode node in tagNodes.SelectNodes ("//tag")) {
720
797
                                string tag = node.InnerText;
721
798
                                tags.Add (tag);
722
799
                        }
723
 
                        
 
800
 
724
801
                        return tags;
725
802
                }
726
803
 
728
805
                {
729
806
                        get {
730
807
                                if (buffer != null)
731
 
                                        return buffer.GetSlice (buffer.StartIter, 
732
 
                                                                buffer.EndIter, 
733
 
                                                                false /* hidden_chars */);
734
 
                                else 
 
808
                                        return buffer.GetSlice (buffer.StartIter,
 
809
                                        buffer.EndIter,
 
810
                                        false /* hidden_chars */);
 
811
                                else
735
812
                                        return XmlDecoder.Decode (XmlContent);
736
813
                        }
737
814
                        set {
740
817
                                else
741
818
                                        Logger.Log ("Setting text content for closed notes not supported");
742
819
                        }
743
 
                                
 
820
 
744
821
                }
745
822
 
746
823
                public NoteData Data
747
824
                {
748
 
                        get { return data.GetDataSynchronized (); }
749
 
                }
750
 
 
751
 
                public DateTime CreateDate 
752
 
                {
753
 
                        get { return data.Data.CreateDate; }
754
 
                }
755
 
 
756
 
                public DateTime ChangeDate 
757
 
                {
758
 
                        get { return data.Data.ChangeDate; }
 
825
                        get {
 
826
                                return data.GetDataSynchronized ();
 
827
                        }
 
828
                }
 
829
 
 
830
                public DateTime CreateDate
 
831
                {
 
832
                        get {
 
833
                                return data.Data.CreateDate;
 
834
                        }
 
835
                }
 
836
 
 
837
                public DateTime ChangeDate
 
838
                {
 
839
                        get {
 
840
                                return data.Data.ChangeDate;
 
841
                        }
759
842
                }
760
843
 
761
844
                public NoteManager Manager
762
845
                {
763
 
                        get { return manager; }
764
 
                        set { manager = value; }
 
846
                        get {
 
847
                                return manager;
 
848
                        }
 
849
                        set {
 
850
                                manager = value;
 
851
                        }
765
852
                }
766
853
 
767
854
                public NoteTagTable TagTable
768
855
                {
769
856
                        get {
770
857
                                if (tag_table == null) {
771
 
#if FIXED_GTKSPELL
 
858
                                        #if FIXED_GTKSPELL
772
859
                                        // NOTE: Sharing the same TagTable means
773
860
                                        // that formatting is duplicated between
774
861
                                        // buffers.
775
862
                                        tag_table = NoteTagTable.Instance;
776
 
#else
 
863
                                        #else
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 ();
783
 
#endif
 
870
                                        #endif
784
871
                                }
785
872
                                return tag_table;
786
873
                        }
788
875
 
789
876
                public bool HasBuffer
790
877
                {
791
 
                        get { return null != buffer; }
 
878
                        get {
 
879
                                return null != buffer;
 
880
                        }
792
881
                }
793
882
 
794
883
                public NoteBuffer Buffer
795
884
                {
796
885
                        get {
797
886
                                if (buffer == null) {
798
 
                                        Logger.Log ("Creating Buffer for '{0}'...", 
799
 
                                                    data.Data.Title);
 
887
                                        Logger.Log ("Creating Buffer for '{0}'...",
 
888
                                        data.Data.Title);
800
889
 
801
890
                                        buffer = new NoteBuffer (TagTable, this);
802
891
                                        data.Buffer = buffer;
813
902
 
814
903
                public bool HasWindow
815
904
                {
816
 
                        get { return null != window; }
 
905
                        get {
 
906
                                return null != window;
 
907
                        }
817
908
                }
818
909
 
819
 
                public NoteWindow Window 
 
910
                public NoteWindow Window
820
911
                {
821
912
                        get {
822
913
                                if (window == null) {
823
914
                                        window = new NoteWindow (this);
824
915
                                        window.Destroyed += WindowDestroyed;
825
916
                                        window.ConfigureEvent += WindowConfigureEvent;
826
 
                                        
 
917
 
827
918
                                        if (data.Data.HasExtent ())
828
 
                                                window.SetDefaultSize (data.Data.Width, 
829
 
                                                                       data.Data.Height);
 
919
                                                window.SetDefaultSize (data.Data.Width,
 
920
                                                                       data.Data.Height);
830
921
 
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 ();
842
933
                                }
843
 
                                return window; 
844
 
                        }
845
 
                }
846
 
 
847
 
                public bool IsSpecial 
848
 
                {
849
 
                        get { return NoteManager.StartNoteUri == data.Data.Uri; }
850
 
                }
851
 
 
852
 
                public bool IsNew 
853
 
                {
854
 
                        get { 
 
934
                                return window;
 
935
                        }
 
936
                }
 
937
 
 
938
                public bool IsSpecial
 
939
                {
 
940
                        get {
 
941
                                return NoteManager.StartNoteUri == data.Data.Uri;
 
942
                        }
 
943
                }
 
944
 
 
945
                public bool IsNew
 
946
                {
 
947
                        get {
855
948
                                // Note is new if created in the last 24 hours.
856
949
                                return data.Data.CreateDate > DateTime.Now.AddHours (-24);
857
950
                        }
858
951
                }
859
952
 
860
 
                public bool IsLoaded 
 
953
                public bool IsLoaded
861
954
                {
862
 
                        get { return buffer != null; }
 
955
                        get {
 
956
                                return buffer != null;
 
957
                        }
863
958
                }
864
959
 
865
 
                public bool IsOpened 
 
960
                public bool IsOpened
866
961
                {
867
 
                        get { return window != null; }
 
962
                        get {
 
963
                                return window != null;
 
964
                        }
868
965
                }
869
966
 
870
967
                public bool IsPinned
871
968
                {
872
969
                        get {
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;
876
973
                        }
877
974
                        set {
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;
882
979
 
883
 
                                if (value == pinned) 
 
980
                                if (value == pinned)
884
981
                                        return;
885
982
 
886
983
                                if (value) {
897
994
                                Preferences.Set (Preferences.MENU_PINNED_NOTES, new_pinned);
898
995
                        }
899
996
                }
900
 
                
 
997
 
901
998
                public bool IsOpenOnStartup
902
999
                {
903
 
                        get { return Data.IsOpenOnStartup; }
 
1000
                        get {
 
1001
                                return Data.IsOpenOnStartup;
 
1002
                        }
904
1003
                        set {
905
1004
                                if (Data.IsOpenOnStartup != value) {
906
1005
                                        Data.IsOpenOnStartup = value;
908
1007
                                }
909
1008
                        }
910
1009
                }
911
 
                
 
1010
 
912
1011
                public List<Tag> Tags
913
1012
                {
914
 
                        get { return new List<Tag> (data.Data.Tags.Values); }
 
1013
                        get {
 
1014
                                return new List<Tag> (data.Data.Tags.Values);
 
1015
                        }
915
1016
                }
916
1017
 
917
1018
                public event EventHandler Opened;
928
1029
        public class NoteArchiver
929
1030
        {
930
1031
                public const string CURRENT_VERSION = "0.2";
931
 
                
 
1032
 
932
1033
                public const string DATE_TIME_FORMAT = "yyyy-MM-ddTHH:mm:ss.fffffffzzz";
933
1034
 
934
1035
                static NoteArchiver instance = null;
962
1063
                        return Instance.ReadFile (read_file, uri);
963
1064
                }
964
1065
 
965
 
                public virtual NoteData ReadFile (string read_file, string uri) 
 
1066
                public virtual NoteData ReadFile (string read_file, string uri)
966
1067
                {
967
1068
                        NoteData note = new NoteData (uri);
968
1069
                        string version = "";
969
1070
 
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;
974
1075
 
988
1089
                                                note.Text = xml.ReadInnerXml ();
989
1090
                                                break;
990
1091
                                        case "last-change-date":
991
 
                                                note.ChangeDate = 
992
 
                                                        XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
 
1092
                                                note.ChangeDate =
 
1093
                                                        XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
993
1094
                                                break;
994
1095
                                        case "create-date":
995
 
                                                note.CreateDate = 
996
 
                                                        XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
 
1096
                                                note.CreateDate =
 
1097
                                                        XmlConvert.ToDateTime (xml.ReadString (), DATE_TIME_FORMAT);
997
1098
                                                break;
998
1099
                                        case "cursor-position":
999
1100
                                                note.CursorPosition = int.Parse (xml.ReadString ());
1043
1144
                        Instance.WriteFile (write_file, note);
1044
1145
                }
1045
1146
 
1046
 
                public virtual void WriteFile (string write_file, NoteData note) 
 
1147
                public virtual void WriteFile (string write_file, NoteData note)
1047
1148
                {
1048
1149
                        string tmp_file = write_file + ".tmp";
1049
1150
 
1088
1189
 
1089
1190
                        xml.WriteStartDocument ();
1090
1191
                        xml.WriteStartElement (null, "note", "http://beatniksoftware.com/tomboy");
1091
 
                        xml.WriteAttributeString(null, 
1092
 
                                                 "version", 
1093
 
                                                 null, 
1094
 
                                                 CURRENT_VERSION);
1095
 
                        xml.WriteAttributeString("xmlns", 
1096
 
                                                 "link", 
1097
 
                                                 null, 
1098
 
                                                 "http://beatniksoftware.com/tomboy/link");
1099
 
                        xml.WriteAttributeString("xmlns", 
1100
 
                                                 "size", 
1101
 
                                                 null, 
1102
 
                                                 "http://beatniksoftware.com/tomboy/size");
 
1192
                        xml.WriteAttributeString(null,
 
1193
                                                 "version",
 
1194
                                                 null,
 
1195
                                                 CURRENT_VERSION);
 
1196
                        xml.WriteAttributeString("xmlns",
 
1197
                                                 "link",
 
1198
                                                 null,
 
1199
                                                 "http://beatniksoftware.com/tomboy/link");
 
1200
                        xml.WriteAttributeString("xmlns",
 
1201
                                                 "size",
 
1202
                                                 null,
 
1203
                                                 "http://beatniksoftware.com/tomboy/size");
1103
1204
 
1104
1205
                        xml.WriteStartElement (null, "title", null);
1105
1206
                        xml.WriteString (note.Title);
1113
1214
 
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 ();
1118
1219
 
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 ();
1124
1225
                        }
1125
1226
 
1142
1243
                        xml.WriteStartElement (null, "y", null);
1143
1244
                        xml.WriteString (note.Y.ToString ());
1144
1245
                        xml.WriteEndElement ();
1145
 
                        
 
1246
 
1146
1247
                        if (note.Tags.Count > 0) {
1147
1248
                                xml.WriteStartElement (null, "tags", null);
1148
1249
                                foreach (Tag tag in note.Tags.Values) {
1152
1253
                                }
1153
1254
                                xml.WriteEndElement ();
1154
1255
                        }
1155
 
                        
 
1256
 
1156
1257
                        xml.WriteStartElement (null, "open-on-startup", null);
1157
1258
                        xml.WriteString (note.IsOpenOnStartup.ToString ());
1158
1259
                        xml.WriteEndElement ();
1160
1261
                        xml.WriteEndElement (); // Note
1161
1262
                        xml.WriteEndDocument ();
1162
1263
                }
1163
 
                
 
1264
 
1164
1265
                // <summary>
1165
1266
                // Parse the tags from the <tags> element
1166
1267
                // </summary>
1167
1268
                List<string> ParseTags (XmlNode tagNodes)
1168
1269
                {
1169
1270
                        List<string> tags = new List<string> ();
1170
 
                        
 
1271
 
1171
1272
                        foreach (XmlNode node in tagNodes.SelectNodes ("//tag")) {
1172
1273
                                string tag = node.InnerText;
1173
1274
                                tags.Add (tag);
1174
1275
                        }
1175
 
                        
 
1276
 
1176
1277
                        return tags;
1177
1278
                }
1178
 
                
 
1279
 
1179
1280
                public virtual string GetRenamedNoteXml (string noteXml, string oldTitle, string newTitle)
1180
1281
                {
1181
1282
                        string updatedXml;
1182
 
                        
 
1283
 
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);
1189
 
                        
 
1290
 
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);
1195
 
                        
 
1296
 
1196
1297
                        return updatedXml;
1197
1298
                }
1198
 
                
 
1299
 
1199
1300
                public virtual string GetTitleFromNoteXml (string noteXml)
1200
1301
                {
1201
1302
                        if (noteXml != null && noteXml.Length > 0) {
1206
1307
                                        switch (xml.NodeType) {
1207
1308
                                        case XmlNodeType.Element:
1208
1309
                                                switch (xml.Name) {
1209
 
                                        case "title":
1210
 
                                                return xml.ReadString ();
1211
 
                                                break;
1212
 
                                        }
 
1310
                                                case "title":
 
1311
                                                        return xml.ReadString ();
 
1312
                                                        break;
 
1313
                                                }
1213
1314
                                                break;
1214
1315
                                        }
1215
1316
                                }
1216
1317
                        }
1217
 
                        
 
1318
 
1218
1319
                        return null;
1219
1320
                }
1220
1321
        }
1221
1322
 
1222
1323
        public class NoteUtils
1223
1324
        {
1224
 
                public static void ShowDeletionDialog (Note note, Gtk.Window parent) 
 
1325
                public static void ShowDeletionDialog (List<Note> notes, Gtk.Window parent)
1225
1326
                {
1226
 
                        HIGMessageDialog dialog = 
1227
 
                                new HIGMessageDialog (
1228
 
                                        parent,
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."));
 
1327
                        string message;
 
1328
                        
 
1329
                        if (notes.Count == 1)
 
1330
                                message = Catalog.GetString ("Really delete this note?");
 
1331
                        else
 
1332
                                message = Catalog.GetString ("Really delete these notes?");
 
1333
                        
 
1334
                        HIGMessageDialog dialog =
 
1335
                                new HIGMessageDialog (
 
1336
                                parent,
 
1337
                                Gtk.DialogFlags.DestroyWithParent,
 
1338
                                Gtk.MessageType.Question,
 
1339
                                Gtk.ButtonsType.None,
 
1340
                                message,
 
1341
                                Catalog.GetString ("If you delete a note it is " +
 
1342
                                                   "permanently lost."));
1235
1343
 
1236
1344
                        Gtk.Button button;
1237
1345
 
1248
1356
 
1249
1357
                        int result = dialog.Run ();
1250
1358
                        if (result == 666) {
1251
 
                                note.Manager.Delete (note);
 
1359
                                foreach (Note note in notes) {
 
1360
                                        note.Manager.Delete (note);
 
1361
                                }
1252
1362
                        }
1253
1363
 
1254
1364
                        dialog.Destroy();