summaryrefslogtreecommitdiff
path: root/cad/src/model/Comment.py
blob: 25ad2a7f5ddd75c99af7eb78b8b83d7eedb2f59c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# Copyright 2004-2008 Nanorex, Inc.  See LICENSE file for details. 
"""
Comment.py - The Comment class.

@version: $Id$
@copyright: 2004-2008 Nanorex, Inc.  See LICENSE file for details. 

History:

mark 060530 - Comment class moved here from Utility.py.

bruce 071019 - moved mmp reading code for Comment into this file;
registering it with files_mmp_registration instead of hardcoding it there
"""

from foundation.Utility import SimpleCopyMixin, Node
from utilities.icon_utilities import imagename_to_pixmap
from utilities.constants import gensym

from files.mmp.files_mmp_registration import MMP_RecordParser
from files.mmp.files_mmp_registration import register_MMP_RecordParser

# ==

class Comment(SimpleCopyMixin, Node):
    """
    A Comment stores a comment in the MMP file, accessible from the Model Tree as a node.
    """
    # text representation: self.lines is a list of lines (str or unicode python strings).
    # This is the fundamental representation for use by mmp read/write, copy, and Undo.
    # For convenience, get_text() and set_text() are also available.

    sym = "Comment"

    lines = ()

    copyable_attrs = Node.copyable_attrs + ('lines',)
        #bruce 060523 this fixes bug 1939 (undo) and apparently 1938 (file modified),
        # and together with SimpleCopyMixin it also fixes bug 1940 (copy) 

    def __init__(self, assy, name, text=''):
        self.const_pixmap = imagename_to_pixmap("modeltree/comment.png")
        if not name:
            name = gensym("%s" % self.sym, assy)
        Node.__init__(self, assy, name)
        self.lines = [] # this makes set_text changed() test legal (result of test doesn't matter)
        self.set_text(text)
        return

    def assert_valid_line(self, line): #bruce 070502
        assert type(line) in (type(""), type(u"")), "invalid type for line = %r, with str = %s" % (line, line)
        return
    
    def set_text(self, text):
        """
        Set our text (represented in self.lines, a list of 1 or more str or unicode strings, no newlines)
        to the lines in the given str or unicode python string, or QString.
        """
        oldlines = self.lines
        if type(text) in (type(""), type(u"")):
            # this (text.split) works for str or unicode text;
            # WARNING: in Qt4 it would also work for QString, but produces QStrings,
            # so we have to do the explicit type test rather than try/except like in Qt3.
            # (I didn't check whether we got away with try/except in Qt3 due to QString.split not working
            #  or due to not being passed a QString in that case.) [bruce 070502 Qt4 bugfix]
            lines = text.split('\n')
        else:
            # it must be a QString
            text = unicode(text)
            ## self.text = text # see if edit still works after this -- it does
            lines = text.split('\n')
            # ok that they are unicode but needn't be? yes.
        map( self.assert_valid_line, lines) 
        self.lines = lines
        if oldlines != lines:
            self.changed()
        return

    def get_text(self):
        """
        return our text (perhaps as a unicode string, whether or not unicode is needed)
        """
        return u'\n'.join(self.lines) #bruce 070502 bugfix: revert Qt4 porting error which broke this for unicode

    def _add_line(self, line, encoding = 'ascii'):
        """
        [private method to support mmp reading (main record and info records)]

        Add the given line (which might be str or unicode, but is assumed to contain no \ns and not be a QString) to our text.
        """
        if encoding == 'utf-8':
            line = line.decode(encoding)
        else:
            if encoding != 'ascii':
                print "Comment._add_line treating unknown encoding as if ascii:", encoding
            # no need to decode
        self.assert_valid_line(line)
        self.lines.append(line)
        self.changed()
        return

    def _init_line1(self, card):
        """
        [private method]

        readmmp helper -- card is entire line of mmp record (perhaps including \n at end)
        """
        # as of 060522 it does end with \n, but we won't assume it does; but we will assume it was written by our writemmp method
        if card[-1] == '\n':
            card = card[:-1]
        # comment (name) encoding1, line1
        junk, rest = card.split(') ', 1)
        try:
            encoding1, line1 = rest.split(' ', 1) # assume ending blank has been preserved, if line was empty
        except:
            # assume ending blank got lost
            encoding1 = rest
            line1 = ""
        self.lines = [] # kluge
        self._add_line( line1, encoding1)
        return

    def readmmp_info_leaf_setitem( self, key, val, interp ): #bruce 060522
        "[extends superclass method]"
        if key[0] == 'commentline' and len(key) == 2:
            # key[1] is the encoding, and val is one line in the comment
            self._add_line(val, key[1])
        else:
            Node.readmmp_info_leaf_setitem( self, key, val, interp)
        return
    
    def edit(self):
        """
        Opens Comment dialog with current text.
        """
        self.assy.w.commentcntl.setup(self)
        
    def writemmp(self, mapping):
        lines = self.lines
        def encodeline(line):
            self.assert_valid_line(line) #k should be redundant, since done whenever we modify self.lines
            try:
                return 'ascii', line.encode('ascii')
            except:
                return 'utf-8', line.encode('utf-8') # needed if it contains unicode characters
            # in future we might have more possibilities, e.g. html or images or links...
        encodedlines = map( encodeline, lines)
        encoding1, line1 = encodedlines[0] # this works even if the comment is empty (1 line, length 0)
        mapping.write("comment (" + mapping.encode_name(self.name) + ") %s %s\n" % (encoding1, line1))
        for encoding1, line1 in encodedlines[1:]:
            mapping.write("info leaf commentline %s = %s\n" % (encoding1, line1))
        self.writemmp_info_leaf(mapping)
        return

    def __str__(self):
        return "<comment " + self.name + ">"
        
    pass # end of class Comment

# ==

class _MMP_RecordParser_for_Comment( MMP_RecordParser): #bruce 071019
    """
    Read the first line of the MMP record for a Comment.
    """
    def read_record(self, card): #bruce 060522
        name = self.get_name(card, "Comment")
        name = self.decode_name(name) #bruce 050618
        comment = Comment(self.assy, name)
        comment._init_line1(card) # card ends with a newline
        self.addmember(comment)
        # Note: subsequent lines of the Comment text (if any)
        # come from info leaf records following this record
        # in the mmp file.
        return
    pass

def register_MMP_RecordParser_for_Comment():
    """
    [call this during init, before reading any mmp files]
    """
    register_MMP_RecordParser( 'comment', _MMP_RecordParser_for_Comment )
    return

# end