Initial revision
[blender.git] / source / blender / bpython / intern / BPY_text.c
1 /** Text buffer module; access to Text buffers in Blender
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30   *
31   * The ownership relations of a Text buffer are in Blender pretty clear:
32   * The Text editor is ALWAYS the container for all text objects.
33   * Currently, the Text object is implemented as a free object though, as
34   * the ownership of a Text might change in future. The reference counting of
35   * a Text object IN BLENDER is not really maintained though (for the above ownership
36   * reason).
37   * This introduces a problem if a Text object is accessed after it was actually
38   * deleted. Currently, a 'guard' is implemented for access after deletion INSIDE 
39   * A SCRIPT. The Blender GUI is not aware of the wrapper though, so if a Text buffer
40   * is cleared while the script is accessing the wrapper, bad results are expected.
41   * BUT: This currently can not happen, unless a Python script is running in the
42   * background as a separate thread...
43   * 
44   * TODO: 
45   * 
46   * either a):
47   *    figure out ownership and implement each access to the text buffer by
48   *    name and not by reference (pointer). This will require quite some additions
49   *    in the generic DataBlock access (opy_datablock.c)
50   * 
51   * or     b):
52   *    implement reference counting for text buffers properly, so that a deletion
53   *    of a text buffer by the GUI does not result in a release of the actual
54   *    Text object, but by a DECREF. The garbage collector (or wrapper deletion method)
55   *    will then free the Text object.
56   * 
57   * To be discussed and evaluated.
58   * 
59   * $Id$
60   *
61   */
62
63
64 #include "Python.h"
65 #include "stringobject.h"
66
67 #include "BPY_macros.h"
68 #include "BKE_text.h"
69 #include "BIF_drawtext.h"
70 #include "DNA_text_types.h"
71 #include "BPY_extern.h"
72 #include "BKE_sca.h"
73
74 #include "b_interface.h"
75 #include "opy_datablock.h"
76
77 DATABLOCK_GET(Textmodule, text object, getTextList())
78
79 #define CHECK_VALIDTEXT(x) CHECK_VALIDDATA(x, \
80         "Text was deleted; illegal access!")
81
82 #define OFF 1
83
84 static char Textmodule_New_doc[] =
85 "(name = None, follow = 0) - Create new text buffer with (optionally given)\n\
86 name.\n\
87 If 'follow' == 1, the text display always follows the cursor";
88
89 static PyObject *Textmodule_New(PyObject *self, PyObject *args)
90 {
91         Text *text;
92         PyObject *textobj;
93         PyObject *name = NULL;
94         int follow = 0;
95
96         text = add_empty_text();
97         BPY_TRY(PyArg_ParseTuple(args, "|O!i", &PyString_Type, &name, &follow));
98         textobj = DataBlock_fromData(text);
99         if (follow) {
100                 text->flags |= TXT_FOLLOW;
101         }
102         if (name) {
103                 DataBlock_setattr(textobj, "name", name);
104         }
105         return textobj;
106 }
107
108 static char Textmodule_unlink_doc[] =
109 "(text) - remove text object 'text' from the text window";
110
111 /** This function removes the text entry from the text editor. 
112   * The text is not freed here, but inside the garbage collector 
113   */
114
115 static PyObject *Textmodule_unlink(PyObject *self, PyObject *args)
116 {
117         PyObject *textobj;
118         Text *text;
119
120         BPY_TRY(PyArg_ParseTuple(args, "O!", &DataBlock_Type, &textobj));
121         if (!DataBlock_isType((DataBlock *) textobj, ID_TXT)) {
122                 PyErr_SetString(PyExc_TypeError, "Text object expected!");
123                 return NULL;
124         }
125
126         text = PYBLOCK_AS_TEXT(textobj);
127         BPY_clear_bad_scriptlinks(text);
128         free_text_controllers(text);
129         unlink_text(text);
130         /* We actually should not free the text object here, but let the
131          * __del__ method of the wrapper do the job. This would require some
132          * changes in the GUI code though.. 
133          * So we mark the wrapper as invalid by setting wrapper->data = 0 */
134         free_libblock(getTextList(), text);
135         MARK_INVALID(textobj);
136
137         Py_INCREF(Py_None);     
138         return Py_None;
139 }
140
141
142 /* these are the module methods */
143 struct PyMethodDef Textmodule_methods[] = {
144         {"get", Textmodule_get, METH_VARARGS, Textmodule_get_doc}, 
145         {"New", Textmodule_New, METH_VARARGS, Textmodule_New_doc},
146         {"unlink", Textmodule_unlink, METH_VARARGS, Textmodule_unlink_doc},
147         {NULL, NULL}
148 };
149
150 // Text object properties
151
152 DataBlockProperty Text_Properties[]= {
153         {NULL}
154 };
155
156 /* This is uncommented only for an example on how (probably) not to
157  * do it :-)
158  * It's a bad idea in this case to have a wrapper object destroy its wrapped object
159  * because checks have to be done whether the wrapper is still accessed after
160  * the wrapped objects deletion. 
161  * Better: unlink the object from it's owner: Blender.Text.unlink(text)
162  * That way the object is not yet freed, but its refcount set to 0.
163  * The garbage collector takes care of the rest..
164  * But it has to be made sure that the wrapper object is no longer kept around
165  * after the script ends.
166  *
167
168 static char Text_delete_doc[] =
169 "() - delete text from Text window";
170
171 static PyObject *Text_delete(PyObject *self, PyObject *args)
172 {
173         Text *text = PYBLOCK_AS_TEXT(self);
174         // we have to check for validity, as the Text object is only a
175         // descriptor...
176         CHECK_VALIDTEXT(text)
177         BPY_TRY(PyArg_ParseTuple(args, ""));
178         BPY_clear_bad_scriptlinks(text);
179         free_text_controllers(text);
180         unlink_text(text);
181         free_libblock(&getGlobal()->main->text, text);
182         ((DataBlock *) self)->data = NULL;
183         Py_INCREF(Py_None);     
184         return Py_None;
185 }
186
187 */
188
189 /** This method gets called on the wrapper objects deletion.
190   * Here we release the Text object if its refcount is == 0
191
192         -- CURRENTLY UNCOMMENTED -- needs change in Blender kernel..
193
194 static PyObject *Text_del(PyObject *self, PyObject *args)
195 {
196         Text *text = PYBLOCK_AS_TEXT(self);
197         if (BOB_REFCNT((ID *) text) == 0) {
198                 free_libblock(&getGlobal()->main->text, text);
199         }       
200         Py_INCREF(Py_None);     
201         return Py_None;
202 }
203 */
204
205 static char Text_clear_doc[] =
206 "() - clear the text buffer";
207
208 static PyObject *Text_clear(PyObject *self, PyObject *args)
209 {
210         Text *text = PYBLOCK_AS_TEXT(self);
211         int oldstate;
212         CHECK_VALIDTEXT(text)
213         
214         oldstate = txt_get_undostate();
215         txt_set_undostate(OFF);
216         txt_sel_all(text);
217         txt_cut_sel(text);
218         txt_set_undostate(oldstate);
219         
220         Py_INCREF(Py_None);     
221         return Py_None;
222 }
223
224 static char Text_set_doc[] =
225 "(name, val) - set attribute name to val";
226
227 static PyObject *Text_set(PyObject *self, PyObject *args)
228 {
229         int ival;
230         char *attr;
231         Text *text = PYBLOCK_AS_TEXT(self);
232
233         BPY_TRY(PyArg_ParseTuple(args, "si", &attr, &ival));
234         if (STREQ("follow_cursor", attr)) {
235                 if (ival) {
236                         text->flags |= TXT_FOLLOW;
237                 } else {
238                         text->flags &= TXT_FOLLOW;
239                 }
240         }       
241         Py_INCREF(Py_None);     
242         return Py_None;
243 }
244
245 static char Text_write_doc[] =
246 "(line) - append string 'line' to the text buffer";
247
248 static PyObject *Text_write(PyObject *self, PyObject *args)
249 {
250         char *str;
251         Text *text = PYBLOCK_AS_TEXT(self);
252         int oldstate;
253
254         CHECK_VALIDTEXT(text)
255
256         BPY_TRY(PyArg_ParseTuple(args, "s", &str));
257         oldstate = txt_get_undostate();
258         txt_insert_buf(text, str);
259         txt_move_eof(text, 0);
260         txt_set_undostate(oldstate);
261
262         Py_INCREF(Py_None);     
263         return Py_None;
264 }
265
266 static char Text_asLines_doc[] =
267 "() - returns the lines of the text buffer as list of strings";
268
269 static PyObject *Text_asLines(PyObject *self, PyObject *args)
270 {
271         TextLine *line;
272         PyObject *list, *ob;
273         Text *text = (Text *) ((DataBlock *) self)->data;
274
275         CHECK_VALIDTEXT(text)
276
277         line = text->lines.first;
278         list= PyList_New(0);
279         while (line) {
280                 ob = Py_BuildValue("s", line->line);
281                 PyList_Append(list, ob);        
282                 line = line->next;
283         }       
284         return list;
285 }
286
287 /* these are the text object methods */
288 struct PyMethodDef Text_methods[] = {
289         {"clear", Text_clear, METH_VARARGS, Text_clear_doc},
290         {"write", Text_write, METH_VARARGS, Text_write_doc},
291         {"set", Text_set, METH_VARARGS, Text_set_doc},
292         {"asLines", Text_asLines, METH_VARARGS, Text_asLines_doc},
293         {NULL, NULL}
294 };
295