~ubuntu-branches/ubuntu/karmic/notecase/karmic

« back to all changes in this revision

Viewing changes to src/DocAction.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Vijay(Vijay)
  • Date: 2007-06-14 00:13:48 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070614001348-z9e2vbgtenb9nhoo
Tags: 1.5.6-0ubuntu1
* New Upstream release 
*  The libgnomevfs2-dev is also added to Build-Depends 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
////////////////////////////////////////////////////////////////////////////
2
 
// NoteCase notes manager project <http://notecase.sf.net>
3
 
//
4
 
// This code is licensed under BSD license.See "license.txt" for more details.
5
 
//
6
 
// File: Defines atomic action performed on NoteCase document 
7
 
//               (base for Undo/Redo framework)
8
 
////////////////////////////////////////////////////////////////////////////
9
 
 
10
 
#include "DocAction.h"
11
 
#include "callbacks.h"
12
 
#include "support.h"
13
 
#include "lib/NoteDocument.h"
14
 
#include "lib/DocumentIterator.h"
15
 
#include "TextView.h"
16
 
#include "lib/debug.h"
17
 
 
18
 
extern NoteDocument g_doc;
19
 
extern GtkWidget *window1;
20
 
extern int g_nActiveNodeIdx;
21
 
extern TextView g_text;
22
 
void set_title_bar(const char *szText);
23
 
void rebuild_gui_tree (int nPID = -1);
24
 
 
25
 
DocAction::DocAction()
26
 
{
27
 
        m_nType = ACT_UNDEFINED;
28
 
        m_pDoc  = NULL;
29
 
        m_bSelected = false;
30
 
        m_nNodeSibling = 0;
31
 
}
32
 
 
33
 
DocAction::~DocAction()
34
 
{
35
 
}
36
 
 
37
 
void DocAction::Redo()
38
 
{
39
 
        switch(m_nType){
40
 
                case ACT_TEXT_INSERT:
41
 
                        DoTextInsert();
42
 
                        break;
43
 
                case ACT_TEXT_DELETE:
44
 
                        DoTextDelete();
45
 
                        break;
46
 
                case ACT_NODE_INSERT:
47
 
                        DoTreeInsert();
48
 
                        break;
49
 
                case ACT_NODE_RENAME:
50
 
                        DoNodeRename();
51
 
                        break;
52
 
                case ACT_TREE_DELETE:
53
 
                        DoTreeDelete();
54
 
                        break;
55
 
                case ACT_TREE_MOVE:
56
 
                        DoTreeMove();
57
 
                        break;  
58
 
                case ACT_TREE_IMPORT:
59
 
                        DoTreeImport();
60
 
                        break;
61
 
                case ACT_TREE_DND:
62
 
                        DoTreeDND(true);
63
 
                        break;
64
 
        }
65
 
}
66
 
 
67
 
void DocAction::Undo()
68
 
{
69
 
        switch(m_nType){
70
 
                case ACT_TEXT_INSERT:
71
 
                        DoTextDelete();
72
 
                        break;
73
 
                case ACT_TEXT_DELETE:
74
 
                        DoTextInsert();
75
 
                        break;
76
 
                case ACT_NODE_INSERT:
77
 
                        DoTreeDelete();
78
 
                        break;
79
 
                case ACT_NODE_RENAME:
80
 
                        DoNodeUnrename();
81
 
                        break;
82
 
                case ACT_TREE_DELETE:
83
 
                        DoTreeInsert();
84
 
                        break;
85
 
                case ACT_TREE_MOVE:
86
 
                        DoTreeUnmove();
87
 
                        break;  
88
 
                case ACT_TREE_IMPORT:
89
 
                        DoTreeUnimport();
90
 
                        break;
91
 
                case ACT_TREE_DND:
92
 
                        DoTreeDND(false);
93
 
                        break;
94
 
        }
95
 
}
96
 
 
97
 
void DocAction::DoTextInsert()
98
 
{
99
 
        InsertNodeText(m_nNodeIndex, m_nTextStartPos, m_strNodeText.c_str());
100
 
        if(m_bSelected){
101
 
                g_text.SelectRange(m_nTextStartPos, m_nTextStartPos+m_strNodeText.size());
102
 
 
103
 
                GtkWidget *textview = lookup_widget(window1, "textview1");
104
 
                gtk_window_set_focus(GTK_WINDOW(window1), textview);
105
 
        }
106
 
}
107
 
 
108
 
void DocAction::DoTextDelete()
109
 
{
110
 
        DeleteNodeText(m_nNodeIndex, m_nTextStartPos, m_strNodeText.size());
111
 
}
112
 
        
113
 
void DocAction::DoTreeInsert()
114
 
{
115
 
        TRACE("UNDO/REDO: insert %d nodes under PID=%d\n", m_objSubTree.GetNodeCount(), m_nNodePID);
116
 
 
117
 
        int nCount = g_doc.GetNodeCount();
118
 
 
119
 
        TRACE("subtree dump:\n");
120
 
        m_objSubTree.Dump();
121
 
        TRACE("UNDO/REDO insert: %d nodes before\n", g_doc.GetNodeCount());     
122
 
        TRACE("UNDO/REDO insert: PID=%d, Sibling=%d\n", m_nNodePID, m_nNodeSibling);    
123
 
        g_doc.Merge(m_objSubTree, m_nNodePID, m_nNodeSibling, true);
124
 
        TRACE("UNDO/REDO insert: %d nodes after\n", g_doc.GetNodeCount());
125
 
        g_doc.Dump();
126
 
        
127
 
        //rebuild affected branch in the gui tree
128
 
        rebuild_gui_tree (m_nNodePID);
129
 
 
130
 
        g_nActiveNodeIdx = -1;  //no selection
131
 
 
132
 
        //select the node in the GUI tree
133
 
        SelectNodeByIdx(nCount);  //select subtree 'root' node in new tree
134
 
}
135
 
 
136
 
void DocAction::DoTreeDelete()
137
 
{
138
 
        TRACE("UNDO/REDO: delete node ID=%d\n", m_nNodeID);
139
 
 
140
 
        TRACE("subtree dump:\n");
141
 
        m_objSubTree.Dump();
142
 
 
143
 
        GtkTreeIter  iter;
144
 
        TreeIterFromID(iter, m_nNodeID);
145
 
 
146
 
        g_doc.NodeDelete(m_nNodeID);
147
 
        
148
 
        g_nActiveNodeIdx = -1;  //no selection
149
 
 
150
 
        //refresh GUI
151
 
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
152
 
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
153
 
 
154
 
        //remove GUI tree node
155
 
        gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
156
 
 
157
 
        //clear edit belonging to selected node
158
 
        g_text.Clear();  // TOFIX only if current node is one of being deleted
159
 
        
160
 
        set_title_bar(_("Untitled"));   //update node title label
161
 
        RefreshMainTitle();
162
 
}
163
 
 
164
 
void DocAction::DoNodeRename()
165
 
{
166
 
        SetNodeTitle(m_nNodeIndex, m_strNodeNameNew.c_str());   //TOFIX recursive index ?
167
 
}
168
 
 
169
 
void DocAction::DoNodeUnrename()
170
 
{
171
 
        SetNodeTitle(m_nNodeIndex, m_strNodeNameOld.c_str());   //TOFIX recursive index ?
172
 
}
173
 
 
174
 
void DocAction::DoTreeMove()
175
 
{
176
 
        SelectNodeByIdx(m_nNodeIndex);//select proper node
177
 
 
178
 
        switch(m_nMoveDirection){
179
 
                case MOVE_LEFT:
180
 
                        do_node_move_left(false);
181
 
                        break;
182
 
                case MOVE_RIGHT:
183
 
                        do_node_move_right(false);
184
 
                        break;
185
 
                case MOVE_UP:
186
 
                        do_node_move_up(false);
187
 
                        break;
188
 
                case MOVE_DOWN:
189
 
                        do_node_move_down(false);
190
 
                        break;
191
 
        }
192
 
}
193
 
 
194
 
//reverse the moving operation
195
 
void DocAction::DoTreeUnmove()
196
 
{
197
 
        int i;
198
 
 
199
 
        SelectNodeByIdx(m_nNodeIndex);//select proper node
200
 
 
201
 
        switch(m_nMoveDirection){
202
 
                case MOVE_LEFT:
203
 
                        do_node_move_right(false);
204
 
                        //restore sibling index position when moving back from left to right
205
 
                        for(i=0; i<m_nNodeSibling; i++) 
206
 
                                do_node_move_down(false);
207
 
                        break;
208
 
                case MOVE_RIGHT:
209
 
                        do_node_move_left(false);
210
 
                        break;
211
 
                case MOVE_UP:
212
 
                        do_node_move_down(false);
213
 
                        break;
214
 
                case MOVE_DOWN:
215
 
                        do_node_move_up(false);
216
 
                        break;
217
 
        }
218
 
}
219
 
 
220
 
void DocAction::DoTreeImport()
221
 
{
222
 
        DocumentIterator it(g_doc);
223
 
        int nCnt = it.GetChildCount(-1);
224
 
 
225
 
        //TOFIX ask user for import details and merge with current document
226
 
        g_doc.Merge(m_objSubTree);
227
 
 
228
 
        //refresh tree starting from new content
229
 
        add_child_nodes(NULL, -1, nCnt);
230
 
}
231
 
 
232
 
void DocAction::DoTreeUnimport()
233
 
{
234
 
        DocumentIterator it(g_doc);
235
 
        int nCount = it.GetNodeCount();
236
 
        int i;
237
 
 
238
 
        g_nActiveNodeIdx = -1;  //no selection
239
 
 
240
 
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
241
 
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
242
 
 
243
 
        //delete all nodes after idx = m_nNodeIndex 
244
 
        //delete in backward direction
245
 
        for(i=nCount-1; i>=m_nNodeIndex; i--)
246
 
        {
247
 
                int nID = g_doc.GetNodeByIdx(i).m_nID;
248
 
 
249
 
                GtkTreeIter  iter;
250
 
                TreeIterFromID(iter, nID);
251
 
 
252
 
                //delete in memory
253
 
                g_doc.NodeDelete(nID);  
254
 
 
255
 
                //remove GUI tree node
256
 
                gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
257
 
 
258
 
                //clear edit belonging to selected node
259
 
                g_text.Clear();  // TOFIX only if current node is one of being deleted
260
 
 
261
 
                //update node title label
262
 
                set_title_bar(_("Untitled"));
263
 
                RefreshMainTitle();
264
 
        }
265
 
}
266
 
 
267
 
void DocAction::DoTreeDND(bool bForward)
268
 
{
269
 
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
270
 
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
271
 
 
272
 
        if(bForward)
273
 
        {
274
 
                //redo - move node branch from original position to new one
275
 
                int nID = m_nNodeID;
276
 
 
277
 
                GtkTreeIter iter;
278
 
                TreeIterFromID(iter, nID);
279
 
 
280
 
                TRACE("REDO dnd: tree dump on start\n");
281
 
                #ifdef _DEBUG
282
 
                        g_doc.Dump();
283
 
                #endif
284
 
 
285
 
                TRACE("REDO dnd: delete node ID=%d\n", nID);
286
 
 
287
 
                //delete in memory
288
 
                g_doc.NodeDelete(nID);  
289
 
 
290
 
                TRACE("REDO dnd: tree dump after delete\n");
291
 
                #ifdef _DEBUG
292
 
                        g_doc.Dump();
293
 
                #endif
294
 
 
295
 
                //remove GUI tree node
296
 
                gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
297
 
 
298
 
                //clear edit belonging to selected node
299
 
                g_text.Clear();  // TOFIX only if current node is one of being deleted
300
 
 
301
 
                TRACE("REDO dnd: merge subtree under PID=%d, SIB=%d\n", m_nNodeNewPID, m_nNodeNewSibling);
302
 
 
303
 
                //insert node branch into new position
304
 
                g_doc.Merge(m_objSubTree, m_nNodeNewPID, m_nNodeNewSibling, true);  //keep IDs
305
 
 
306
 
                TRACE("REDO dnd: tree dump after merge\n");
307
 
                #ifdef _DEBUG
308
 
                        g_doc.Dump();
309
 
                #endif
310
 
 
311
 
                //rebuild GUI
312
 
                rebuild_gui_tree (m_nNodeNewPID);
313
 
        }
314
 
        else
315
 
        {
316
 
                //undo - move new node branch back to original position
317
 
                int nID = m_nNewNodeID;
318
 
 
319
 
                GtkTreeIter iter;
320
 
                TreeIterFromID(iter, nID);
321
 
 
322
 
                TRACE("UNDO dnd: tree dump on start\n");
323
 
                #ifdef _DEBUG
324
 
                        g_doc.Dump();
325
 
                #endif
326
 
 
327
 
                TRACE("UNDO dnd: delete node ID=%d\n", nID);
328
 
 
329
 
                //delete in memory
330
 
                g_doc.NodeDelete(nID);  
331
 
 
332
 
                TRACE("UNDO dnd: tree dump after delete\n");
333
 
                #ifdef _DEBUG
334
 
                        g_doc.Dump();
335
 
                #endif
336
 
 
337
 
                //remove GUI tree node
338
 
                gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
339
 
 
340
 
                //clear edit belonging to selected node
341
 
                g_text.Clear();  // TOFIX only if current node is one of being deleted
342
 
 
343
 
                TRACE("UNDO dnd: merge subtree under PID=%d\n", m_nNodePID);
344
 
 
345
 
                //insert node branch into original position
346
 
                g_doc.Merge(m_objSubTree, m_nNodePID, m_nNodeSibling, true);    //keep IDs
347
 
 
348
 
                TRACE("UNDO dnd: tree dump after merge\n");
349
 
                #ifdef _DEBUG
350
 
                        g_doc.Dump();
351
 
                #endif
352
 
 
353
 
                //rebuild GUI
354
 
                rebuild_gui_tree (m_nNodePID);
355
 
        }
356
 
}
357
 
 
358
 
void rebuild_gui_tree (int nPID)
359
 
{
360
 
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
361
 
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
362
 
 
363
 
        if(nPID == -1)
364
 
        {
365
 
                //clear all nodes
366
 
                gtk_tree_store_clear(GTK_TREE_STORE(model));
367
 
 
368
 
                //rebuild parent node children
369
 
                add_child_nodes(NULL, nPID, 0);
370
 
        }
371
 
        else
372
 
        {
373
 
                GtkTreeIter iter;
374
 
                TreeIterFromID(iter, nPID);
375
 
 
376
 
                //remove all parent node children
377
 
                GtkTreeIter iterChild;
378
 
                while(gtk_tree_model_iter_children(model, &iterChild, &iter))
379
 
                        gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild); //delete all children
380
 
 
381
 
                //rebuild parent node children
382
 
                add_child_nodes(&iter, nPID, 0);
383
 
        }
384
 
}
385
 
 
 
1
////////////////////////////////////////////////////////////////////////////
 
2
// NoteCase notes manager project <http://notecase.sf.net>
 
3
//
 
4
// This code is licensed under BSD license.See "license.txt" for more details.
 
5
//
 
6
// File: Defines atomic action performed on NoteCase document 
 
7
//               (base for Undo/Redo framework)
 
8
////////////////////////////////////////////////////////////////////////////
 
9
 
 
10
#include "DocAction.h"
 
11
#include "callbacks.h"
 
12
#include "support.h"
 
13
#include "interface.h"
 
14
#include "lib/NoteDocument.h"
 
15
#include "lib/DocumentIterator.h"
 
16
#include "TextView.h"
 
17
#include "TreeView.h"
 
18
#include "lib/debug.h"
 
19
 
 
20
extern NoteDocument g_doc;
 
21
extern GtkWidget *window1;
 
22
extern TextView g_text;
 
23
extern TreeView g_tree;
 
24
 
 
25
void rebuild_gui_tree (int nPID = -1);
 
26
bool IteratorFromNodeIdx(int nIdx, GtkTreeIter &iter);
 
27
void RefreshAllLinkTags();
 
28
int GetSelectedNodeIdx();
 
29
 
 
30
DocAction::DocAction()
 
31
{
 
32
        m_nType = ACT_UNDEFINED;
 
33
        m_bSelected = false;
 
34
        m_nNodeSibling = 0;
 
35
        m_nOffset = -1;
 
36
        m_bNodeTitle = false;
 
37
        m_nLinkNodeID = -1;
 
38
}
 
39
 
 
40
DocAction::~DocAction()
 
41
{
 
42
}
 
43
 
 
44
void DocAction::Exec(bool bInteractive)
 
45
{
 
46
        switch(m_nType){
 
47
                case ACT_TEXT_INSERT:
 
48
                        DoTextInsert();
 
49
                        break;
 
50
                case ACT_TEXT_DELETE:
 
51
                        DoTextDelete();
 
52
                        break;
 
53
                case ACT_NODE_INSERT:
 
54
                        DoTreeInsert();
 
55
                        break;
 
56
                case ACT_NODE_RENAME:
 
57
                        DoNodeRename();
 
58
                        break;
 
59
                case ACT_TREE_DELETE:
 
60
                        DoTreeDelete();
 
61
                        break;
 
62
                case ACT_TREE_MOVE:
 
63
                        DoTreeMove();
 
64
                        break;  
 
65
                case ACT_TREE_IMPORT:
 
66
                        DoTreeImport();
 
67
                        break;
 
68
                case ACT_TREE_DND:
 
69
                        DoTreeDND(true);
 
70
                        break;
 
71
                case ACT_TEXT_REPLACE:
 
72
                        DoTextReplace();
 
73
                        break;
 
74
                case ACT_TEXT_LINK_ADD:
 
75
                        DoLinkAdd();
 
76
                        break;
 
77
                case ACT_TEXT_LINK_REMOVE:
 
78
                        DoLinkRemove();
 
79
                        break;
 
80
        }
 
81
}
 
82
 
 
83
void DocAction::Undo()
 
84
{
 
85
        switch(m_nType){
 
86
                case ACT_TEXT_INSERT:
 
87
                        DoTextDelete();
 
88
                        break;
 
89
                case ACT_TEXT_DELETE:
 
90
                        DoTextInsert();
 
91
                        break;
 
92
                case ACT_NODE_INSERT:
 
93
                        DoTreeDelete();
 
94
                        break;
 
95
                case ACT_NODE_RENAME:
 
96
                        DoNodeUnrename();
 
97
                        break;
 
98
                case ACT_TREE_DELETE:
 
99
                        DoTreeInsert();
 
100
                        break;
 
101
                case ACT_TREE_MOVE:
 
102
                        DoTreeUnmove();
 
103
                        break;  
 
104
                case ACT_TREE_IMPORT:
 
105
                        DoTreeUnimport();
 
106
                        break;
 
107
                case ACT_TREE_DND:
 
108
                        DoTreeDND(false);
 
109
                        break;
 
110
                case ACT_TEXT_REPLACE:
 
111
                        DoTextUnreplace();
 
112
                        break;
 
113
                case ACT_TEXT_LINK_ADD:
 
114
                        DoLinkRemove();
 
115
                        break;
 
116
                case ACT_TEXT_LINK_REMOVE:
 
117
                        DoLinkAdd();
 
118
                        break;
 
119
        }
 
120
}
 
121
 
 
122
void DocAction::DoTextInsert()
 
123
{
 
124
        InsertNodeText(m_nNodeIndex, m_nTextStartPos, m_strNodeText.c_str());
 
125
        if(m_bSelected){
 
126
                g_text.SelectRange(m_nTextStartPos, m_nTextStartPos+m_strNodeText.size());
 
127
 
 
128
                GtkWidget *textview = lookup_widget(window1, "textview1");
 
129
                gtk_window_set_focus(GTK_WINDOW(window1), textview);
 
130
        }
 
131
}
 
132
 
 
133
void DocAction::DoTextDelete()
 
134
{
 
135
        DeleteNodeText(m_nNodeIndex, m_nTextStartPos, m_strNodeText.size());
 
136
}
 
137
 
 
138
void DocAction::DoTextReplace()
 
139
{
 
140
        TRACE("UNDO/REDO: replace text\n");
 
141
 
 
142
        SelectNodeByIdx(m_nNodeIndex);//select proper node
 
143
 
 
144
        //TOFIX this code is similar to the one in replace dialog - use this only?
 
145
        int nLen = g_utf8_strlen(m_strFind.c_str(), -1);
 
146
 
 
147
        NoteNode &node = g_doc.GetNodeByIdx(m_nNodeIndex);
 
148
 
 
149
        // some text selected, replace it with the given string
 
150
        std::string strTxt;
 
151
        if(m_bNodeTitle)
 
152
                strTxt = node.GetTitle();
 
153
        else
 
154
                strTxt = node.GetText();
 
155
 
 
156
        //convert from character offset to buffer offset
 
157
        int nCursorBuf, nSelBuf;
 
158
        const char *szBuf = strTxt.c_str();
 
159
        gchar* pszPos = g_utf8_offset_to_pointer(szBuf, m_nOffset);
 
160
        nCursorBuf = pszPos - szBuf;
 
161
        nSelBuf = m_nOffset + nLen;
 
162
        
 
163
        //now replace the text part with new content
 
164
        //TOFIX what if cursor < nSelBuf - convert both values using min
 
165
        strTxt = strTxt.erase(nCursorBuf, nSelBuf-nCursorBuf);
 
166
        strTxt.insert(nCursorBuf, m_strReplace.c_str());
 
167
 
 
168
        if(m_bNodeTitle)
 
169
        {
 
170
                node.SetTitle(strTxt.c_str());
 
171
 
 
172
                //update GUI text
 
173
                GtkTreeIter iter;
 
174
                IteratorFromNodeIdx(m_nNodeIndex, iter);
 
175
                GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)g_tree.m_pWidget);
 
176
                gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 0, strTxt.c_str(), -1);
 
177
 
 
178
                set_title_bar(strTxt.c_str());
 
179
        }
 
180
        else
 
181
        {
 
182
                node.SetText(strTxt.c_str());
 
183
 
 
184
                //update GUI text
 
185
                GtkTextView *textview =  (GtkTextView *)g_text.m_pWidget;
 
186
                GtkTextBuffer* buffer1 = gtk_text_view_get_buffer(textview);
 
187
 
 
188
                g_signal_handlers_block_by_func(buffer1, (void *)on_delete_text, 0);
 
189
                g_signal_handlers_block_by_func(buffer1, (void *)on_insert_text, 0);
 
190
 
 
191
                g_text.ReplaceText(m_nOffset, m_nOffset+nLen, m_strReplace.c_str());
 
192
                g_text.SelectRange(m_nOffset, m_nOffset+g_utf8_strlen(m_strReplace.c_str(), -1));
 
193
 
 
194
                g_signal_handlers_unblock_by_func(buffer1, (void *)on_delete_text, 0);
 
195
                g_signal_handlers_unblock_by_func(buffer1, (void *)on_insert_text, 0);
 
196
 
 
197
                node.OnTxtReplaced(m_nOffset, m_nOffset+nLen, m_strReplace.c_str());
 
198
                RefreshAllLinkTags();
 
199
        }
 
200
}
 
201
 
 
202
void DocAction::DoTextUnreplace()
 
203
{
 
204
        TRACE("UNDO/REDO: undo replace text\n");
 
205
        
 
206
        SelectNodeByIdx(m_nNodeIndex);//select proper node
 
207
 
 
208
        //TOFIX this code is similar to the one in replace dialog - use this only?
 
209
        int nLen = g_utf8_strlen(m_strReplace.c_str(), -1);
 
210
 
 
211
        NoteNode &node = g_doc.GetNodeByIdx(m_nNodeIndex);
 
212
 
 
213
        // some text selected, replace it with the given string
 
214
        std::string strTxt;
 
215
        if(m_bNodeTitle)
 
216
                strTxt = node.GetTitle();
 
217
        else
 
218
                strTxt = node.GetText();
 
219
 
 
220
        //convert from character offset to buffer offset
 
221
        int nCursorBuf, nSelBuf;
 
222
        const char *szBuf = strTxt.c_str();
 
223
        gchar* pszPos = g_utf8_offset_to_pointer(szBuf, m_nOffset);
 
224
        nCursorBuf = pszPos - szBuf;
 
225
        nSelBuf = m_nOffset + nLen;
 
226
        
 
227
        //now replace the text part with new content
 
228
        //TOFIX what if cursor < nSelBuf - convert both values using min
 
229
        strTxt = strTxt.erase(nCursorBuf, nSelBuf-nCursorBuf);
 
230
        strTxt.insert(nCursorBuf, m_strFind.c_str());
 
231
 
 
232
        if(m_bNodeTitle)
 
233
        {
 
234
                node.SetTitle(strTxt.c_str());
 
235
 
 
236
                //update GUI text
 
237
                GtkTreeIter iter;
 
238
                IteratorFromNodeIdx(m_nNodeIndex, iter);
 
239
                GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)g_tree.m_pWidget);
 
240
                gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 0, strTxt.c_str(), -1);
 
241
 
 
242
                set_title_bar(strTxt.c_str());
 
243
        }
 
244
        else
 
245
        {
 
246
                node.SetText(strTxt.c_str());
 
247
 
 
248
                //update GUI text
 
249
                GtkTextView *textview =  (GtkTextView *)g_text.m_pWidget;
 
250
                GtkTextBuffer* buffer1 = gtk_text_view_get_buffer(textview);
 
251
 
 
252
                g_signal_handlers_block_by_func(buffer1, (void *)on_delete_text, 0);
 
253
                g_signal_handlers_block_by_func(buffer1, (void *)on_insert_text, 0);
 
254
 
 
255
                g_text.ReplaceText(m_nOffset, m_nOffset+nLen, m_strFind.c_str());
 
256
                g_text.SelectRange(m_nOffset, m_nOffset + g_utf8_strlen(m_strFind.c_str(), -1));
 
257
 
 
258
                g_signal_handlers_unblock_by_func(buffer1, (void *)on_delete_text, 0);
 
259
                g_signal_handlers_unblock_by_func(buffer1, (void *)on_insert_text, 0);
 
260
 
 
261
                node.OnTxtReplaced(m_nOffset, m_nOffset+nLen, m_strFind.c_str());
 
262
                RefreshAllLinkTags();
 
263
        }
 
264
}
 
265
        
 
266
void DocAction::DoTreeInsert()
 
267
{
 
268
        TRACE("UNDO/REDO: insert %d nodes under PID=%d\n", m_objSubTree.GetNodeCount(), m_nNodePID);
 
269
 
 
270
        int nCount = g_doc.GetNodeCount();
 
271
 
 
272
        TRACE("subtree dump:\n");
 
273
        m_objSubTree.Dump();
 
274
        TRACE("UNDO/REDO insert: %d nodes before\n", g_doc.GetNodeCount());     
 
275
        TRACE("UNDO/REDO insert: PID=%d, Sibling=%d\n", m_nNodePID, m_nNodeSibling);    
 
276
        g_doc.Merge(m_objSubTree, m_nNodePID, m_nNodeSibling, true);
 
277
        TRACE("UNDO/REDO insert: %d nodes after\n", g_doc.GetNodeCount());
 
278
        
 
279
        //rebuild affected branch in the gui tree
 
280
        rebuild_gui_tree (m_nNodePID);
 
281
 
 
282
        g_doc.m_nActiveNodeIdx = -1;    //no selection
 
283
 
 
284
        //select the node in the GUI tree
 
285
        SelectNodeByIdx(nCount);  //select subtree 'root' node in new tree
 
286
}
 
287
 
 
288
void DocAction::DoTreeDelete()
 
289
{
 
290
        TRACE("UNDO/REDO: delete node ID=%d\n", m_nNodeID);
 
291
 
 
292
        TRACE("subtree dump:\n");
 
293
        m_objSubTree.Dump();
 
294
 
 
295
        GtkTreeIter  iter;
 
296
        TreeIterFromID(iter, m_nNodeID);
 
297
 
 
298
        g_doc.NodeDelete(m_nNodeID);
 
299
        
 
300
        g_doc.m_nActiveNodeIdx = -1;    //no selection
 
301
 
 
302
        //refresh GUI
 
303
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
 
304
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
 
305
 
 
306
        //remove GUI tree node
 
307
        gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
 
308
 
 
309
        //clear edit belonging to selected node
 
310
        g_text.Clear();
 
311
        
 
312
        set_title_bar("");      //update node title label
 
313
        RefreshMainTitle();
 
314
}
 
315
 
 
316
void DocAction::DoNodeRename()
 
317
{
 
318
        SetNodeTitle(m_nNodeIndex, m_strNodeNameNew.c_str());   //TOFIX recursive index ?
 
319
}
 
320
 
 
321
void DocAction::DoNodeUnrename()
 
322
{
 
323
        SetNodeTitle(m_nNodeIndex, m_strNodeNameOld.c_str());   //TOFIX recursive index ?
 
324
}
 
325
 
 
326
void DocAction::DoTreeMove()
 
327
{
 
328
        SelectNodeByIdx(m_nNodeIndex);//select proper node
 
329
 
 
330
        switch(m_nMoveDirection){
 
331
                case MOVE_LEFT:
 
332
                        do_node_move_left(false);
 
333
                        break;
 
334
                case MOVE_RIGHT:
 
335
                        do_node_move_right(false);
 
336
                        break;
 
337
                case MOVE_UP:
 
338
                        do_node_move_up(false);
 
339
                        break;
 
340
                case MOVE_DOWN:
 
341
                        do_node_move_down(false);
 
342
                        break;
 
343
        }
 
344
}
 
345
 
 
346
//reverse the moving operation
 
347
void DocAction::DoTreeUnmove()
 
348
{
 
349
        int i;
 
350
 
 
351
        SelectNodeByIdx(m_nNodeIndex);//select proper node
 
352
 
 
353
        switch(m_nMoveDirection){
 
354
                case MOVE_LEFT:
 
355
                        do_node_move_right(false);
 
356
                        //restore sibling index position when moving back from left to right
 
357
                        for(i=0; i<m_nNodeSibling; i++) 
 
358
                                do_node_move_down(false);
 
359
                        break;
 
360
                case MOVE_RIGHT:
 
361
                        do_node_move_left(false);
 
362
                        break;
 
363
                case MOVE_UP:
 
364
                        do_node_move_down(false);
 
365
                        break;
 
366
                case MOVE_DOWN:
 
367
                        do_node_move_up(false);
 
368
                        break;
 
369
        }
 
370
}
 
371
 
 
372
void DocAction::DoTreeImport()
 
373
{
 
374
        DocumentIterator it(g_doc);
 
375
        int nCnt = it.GetChildCount(-1);
 
376
 
 
377
        //TOFIX ask user for import details and merge with current document
 
378
        g_doc.Merge(m_objSubTree);
 
379
 
 
380
        //refresh tree starting from new content
 
381
        add_child_nodes(NULL, -1, nCnt);
 
382
}
 
383
 
 
384
void DocAction::DoTreeUnimport()
 
385
{
 
386
        DocumentIterator it(g_doc);
 
387
        int nCount = g_doc.GetNodeCount();
 
388
        int i;
 
389
 
 
390
        g_doc.m_nActiveNodeIdx = -1;    //no selection
 
391
 
 
392
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
 
393
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
 
394
 
 
395
        //delete all nodes after idx = m_nNodeIndex 
 
396
        //delete in backward direction
 
397
        for(i=nCount-1; i>=m_nNodeIndex; i--)
 
398
        {
 
399
                int nID = g_doc.GetNodeByIdx(i).m_nID;
 
400
 
 
401
                GtkTreeIter  iter;
 
402
                TreeIterFromID(iter, nID);
 
403
 
 
404
                //delete in memory
 
405
                g_doc.NodeDelete(nID);  
 
406
 
 
407
                //remove GUI tree node
 
408
                gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
 
409
 
 
410
                //clear edit belonging to selected node
 
411
                g_text.Clear();  // TOFIX only if current node is one of being deleted
 
412
 
 
413
                //update node title label
 
414
                set_title_bar("");
 
415
                RefreshMainTitle();
 
416
        }
 
417
}
 
418
 
 
419
void DocAction::DoTreeDND(bool bForward)
 
420
{
 
421
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
 
422
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
 
423
 
 
424
        if(bForward)
 
425
        {
 
426
                //redo - move node branch from original position to new one
 
427
                int nID = m_nNodeID;
 
428
 
 
429
                GtkTreeIter iter;
 
430
                TreeIterFromID(iter, nID);
 
431
 
 
432
                TRACE("REDO dnd: tree dump on start\n");
 
433
                #ifdef _DEBUG
 
434
                        g_doc.Dump();
 
435
                #endif
 
436
 
 
437
                TRACE("REDO dnd: delete node ID=%d\n", nID);
 
438
 
 
439
                //delete in memory
 
440
                g_doc.NodeDelete(nID);  
 
441
 
 
442
                TRACE("REDO dnd: tree dump after delete\n");
 
443
                #ifdef _DEBUG
 
444
                        g_doc.Dump();
 
445
                #endif
 
446
 
 
447
                //remove GUI tree node
 
448
                gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
 
449
 
 
450
                //clear edit belonging to selected node
 
451
                g_text.Clear();
 
452
 
 
453
                TRACE("REDO dnd: merge subtree under PID=%d, SIB=%d\n", m_nNodeNewPID, m_nNodeNewSibling);
 
454
 
 
455
                //insert node branch into new position
 
456
                g_doc.Merge(m_objSubTree, m_nNodeNewPID, m_nNodeNewSibling, true);  //keep IDs
 
457
 
 
458
                TRACE("REDO dnd: tree dump after merge\n");
 
459
                #ifdef _DEBUG
 
460
                        g_doc.Dump();
 
461
                #endif
 
462
 
 
463
                //rebuild GUI
 
464
                rebuild_gui_tree (m_nNodeNewPID);
 
465
        }
 
466
        else
 
467
        {
 
468
                //undo - move new node branch back to original position
 
469
                int nID = m_nNewNodeID;
 
470
 
 
471
                GtkTreeIter iter;
 
472
                TreeIterFromID(iter, nID);
 
473
 
 
474
                TRACE("UNDO dnd: tree dump on start\n");
 
475
                #ifdef _DEBUG
 
476
                        g_doc.Dump();
 
477
                #endif
 
478
 
 
479
                TRACE("UNDO dnd: delete node ID=%d\n", nID);
 
480
 
 
481
                //delete in memory
 
482
                g_doc.NodeDelete(nID);  
 
483
 
 
484
                TRACE("UNDO dnd: tree dump after delete\n");
 
485
                #ifdef _DEBUG
 
486
                        g_doc.Dump();
 
487
                #endif
 
488
 
 
489
                //remove GUI tree node
 
490
                gtk_tree_store_remove(GTK_TREE_STORE(model), &iter); 
 
491
 
 
492
                //clear edit belonging to selected node
 
493
                g_text.Clear();
 
494
 
 
495
                TRACE("UNDO dnd: merge subtree under PID=%d, SIdx=%d\n", m_nNodePID, m_nNodeSibling);
 
496
 
 
497
                #ifdef _DEBUG
 
498
                        //m_objSubTree.Dump();
 
499
                #endif
 
500
                //insert node branch into original position
 
501
                g_doc.Merge(m_objSubTree, m_nNodePID, m_nNodeSibling, true);    //keep IDs
 
502
 
 
503
                TRACE("UNDO dnd: tree dump after merge\n");
 
504
                #ifdef _DEBUG
 
505
                        g_doc.Dump();
 
506
                #endif
 
507
 
 
508
                //rebuild GUI
 
509
                rebuild_gui_tree (m_nNodePID);
 
510
        }
 
511
}
 
512
 
 
513
void rebuild_gui_tree (int nPID)
 
514
{
 
515
        GtkTreeView *treeview = (GtkTreeView *)lookup_widget(window1, "treeview1");
 
516
        GtkTreeModel *model = gtk_tree_view_get_model((GtkTreeView *)treeview);
 
517
 
 
518
        if(nPID == -1)
 
519
        {
 
520
                //clear all nodes
 
521
                gtk_tree_store_clear(GTK_TREE_STORE(model));
 
522
 
 
523
                //rebuild parent node children
 
524
                add_child_nodes(NULL, nPID, 0);
 
525
        }
 
526
        else
 
527
        {
 
528
                GtkTreeIter iter;
 
529
                TreeIterFromID(iter, nPID);
 
530
 
 
531
                //remove all parent node children
 
532
                GtkTreeIter iterChild;
 
533
                while(gtk_tree_model_iter_children(model, &iterChild, &iter))
 
534
                        gtk_tree_store_remove(GTK_TREE_STORE(model), &iterChild); //delete all children
 
535
 
 
536
                //rebuild parent node children
 
537
                add_child_nodes(&iter, nPID, 0);
 
538
        }
 
539
}
 
540
 
 
541
void DocAction::DoLinkAdd()
 
542
{
 
543
        LinkInfo info;
 
544
        info.m_nStartOffset = m_nLinkOffset;
 
545
        info.m_strText = m_strLinkTitle;
 
546
        info.m_strTargetURL = m_strLinkUrl;
 
547
        info.m_nTargetNodeID = m_nLinkNodeID;
 
548
        info.RefreshLength();
 
549
 
 
550
        // add link into the node
 
551
        g_doc.GetNodeByIdx(m_nNodeIndex).m_lstLinks.push_back(info);
 
552
 
 
553
        //fix gui display
 
554
        int nIdx = GetSelectedNodeIdx();
 
555
        if(nIdx == m_nNodeIndex)
 
556
        {
 
557
                //underline the text as a link
 
558
                g_text.RemoveTextStyles(info.m_nStartOffset, info.m_nStartOffset+info.m_nTextLength);
 
559
                g_text.SetTextUnderlined(info.m_nStartOffset, info.m_nStartOffset+info.m_nTextLength);
 
560
        }
 
561
}
 
562
 
 
563
void DocAction::DoLinkRemove()
 
564
{
 
565
        NoteNode &node = g_doc.GetNodeByIdx(m_nNodeIndex);
 
566
 
 
567
        //find link info
 
568
        int nPos = node.m_lstLinks.Find(m_nLinkOffset);
 
569
        if(nPos >= 0)
 
570
        {
 
571
                LinkInfo info;
 
572
                info = node.m_lstLinks[nPos];
 
573
 
 
574
                //fix gui display
 
575
                int nIdx = GetSelectedNodeIdx();
 
576
                if(nIdx == m_nNodeIndex)
 
577
                {
 
578
                        g_text.RemoveTextStyles(info.m_nStartOffset, info.m_nStartOffset+info.m_nTextLength);
 
579
                }
 
580
 
 
581
                //remove link from the storage
 
582
                node.m_lstLinks.erase(g_doc.GetNodeByIdx(nIdx).m_lstLinks.begin()+nPos);
 
583
        }
 
584
}
 
585