1 /* libobby - Network text editing library
2 * Copyright (C) 2005, 2006 0x539 dev group
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef _OBBY_SPLIT_OPERATION_HPP_
20 #define _OBBY_SPLIT_OPERATION_HPP_
21
22 #include "operation.hpp"
23
24 namespace obby
25 {
26
27 /** split_operation is a wrapper around two other operations. If an
28 * insert_operation occurs in the range of a delete_operation, the
29 * delete_operation has to be splitted into two delete_operations.
30 */
31 template<typename Document>
32 class split_operation: public operation<Document>
33 {
34 public:
35 typedef operation<Document> operation_type;
36 typedef typename operation_type::document_type document_type;
37
38 /** Constructor taking a copy of both given operations.
39 */
40 split_operation(const operation_type& first,
41 const operation_type& second);
42
43 /** Constructor taking the ownership of both operations instead of
44 * making a copy.
45 */
46 split_operation(std::auto_ptr<operation_type> first,
47 std::auto_ptr<operation_type> second);
48
49 /** Reads a split_operation from the given network packet.
50 */
51 split_operation(const net6::packet& pack,
52 unsigned int& index,
53 const user_table& user_table);
54
55 /** Creates a copy of this operation.
56 */
57 virtual operation_type* clone() const;
58
59 /** Creates the reverse operation of this one.
60 * @param doc Document to receive additional information from.
61 */
62 virtual operation_type* reverse(const document_type& doc) const;
63
64 /** Applies this operation to a document. The split_operation just
65 * forwards this request to both wrapped operations.
66 */
67 virtual void apply(document_type& doc, const user* author) const;
68
69 /** Transforms <em>base_op</em> against this operation. This function
70 * transforms base_op against both wrapped operations.
71 */
72 virtual operation_type* transform(const operation_type& base_op) const;
73
74 /** Includes the effect of the given insertion into this operation.
75 * Both wrapped operations will be transformed.
76 */
77 virtual operation_type* transform_insert(position pos,
78 const std::string& text) const;
79
80 /** Includes the effect of the given deletion into this operation.
81 * Both wrapped operations will be transformed.
82 */
83 virtual operation_type* transform_delete(position pos,
84 position len) const;
85
86 /** Appends the operation to the given packet.
87 */
88 virtual void append_packet(net6::packet& pack) const;
89 protected:
90 std::auto_ptr<operation_type> m_first;
91 std::auto_ptr<operation_type> m_second;
92 };
93
94 template<typename Document>
split_operation(const operation_type & first,const operation_type & second)95 split_operation<Document>::split_operation(const operation_type& first,
96 const operation_type& second):
97 operation<Document>(), m_first(first.clone() ),
98 m_second(second.clone() )
99 {
100 }
101
102 template<typename Document>
103 split_operation<Document>::
split_operation(std::auto_ptr<operation_type> first,std::auto_ptr<operation_type> second)104 split_operation(std::auto_ptr<operation_type> first,
105 std::auto_ptr<operation_type> second):
106 operation<Document>(), m_first(first), m_second(second)
107 {
108 }
109
110 template<typename Document>
split_operation(const net6::packet & pack,unsigned int & index,const user_table & user_table)111 split_operation<Document>::split_operation(const net6::packet& pack,
112 unsigned int& index,
113 const user_table& user_table):
114 operation<Document>(),
115 m_first(
116 operation<Document>::from_packet(
117 pack,
118 index,
119 user_table
120 ).release()
121 ),
122 m_second(operation<Document>::from_packet(
123 pack,
124 index,
125 user_table
126 ).release()
127 )
128 {
129 }
130
131 template<typename Document>
132 typename split_operation<Document>::operation_type*
clone() const133 split_operation<Document>::clone() const
134 {
135 return new split_operation<Document>(*m_first, *m_second);
136 }
137
138 template<typename Document>
139 typename split_operation<Document>::operation_type*
reverse(const document_type & doc) const140 split_operation<Document>::reverse(const document_type& doc) const
141 {
142 return new split_operation<Document>(
143 std::auto_ptr<operation_type>(m_first->reverse(doc) ),
144 std::auto_ptr<operation_type>(m_second->reverse(doc) )
145 );
146 }
147
148 template<typename Document>
apply(document_type & doc,const user * author) const149 void split_operation<Document>::apply(document_type& doc,
150 const user* author) const
151 {
152 m_first->apply(doc, author);
153
154 // Transform second operation because first has just been applied
155 std::auto_ptr<operation_type> second(m_first->transform(*m_second) );
156 second->apply(doc, author);
157 }
158
159 template<typename Document>
160 typename split_operation<Document>::operation_type*
transform(const operation_type & base_op) const161 split_operation<Document>::transform(const operation_type& base_op) const
162 {
163 std::auto_ptr<operation_type> op1(m_second->transform(base_op) );
164 return m_first->transform(*op1);
165 }
166
167 template<typename Document>
168 typename split_operation<Document>::operation_type*
transform_insert(position pos,const std::string & text) const169 split_operation<Document>::transform_insert(position pos,
170 const std::string& text) const
171 {
172 return new split_operation<Document>(
173 std::auto_ptr<operation_type>(
174 m_first->transform_insert(pos, text)
175 ),
176 std::auto_ptr<operation_type>(
177 m_second->transform_insert(pos, text)
178 )
179 );
180 }
181
182 template<typename Document>
183 typename split_operation<Document>::operation_type*
transform_delete(position pos,position len) const184 split_operation<Document>::transform_delete(position pos,
185 position len) const
186 {
187 return new split_operation<Document>(
188 std::auto_ptr<operation_type>(
189 m_first->transform_delete(pos, len)
190 ),
191 std::auto_ptr<operation_type>(
192 m_second->transform_delete(pos, len)
193 )
194 );
195 }
196
197 template<typename Document>
append_packet(net6::packet & pack) const198 void split_operation<Document>::append_packet(net6::packet& pack) const
199 {
200 pack << "split";
201 m_first->append_packet(pack);
202 m_second->append_packet(pack);
203 }
204
205 } // namespace obby
206
207 #endif // _OBBY_SPLIT_OPERATION_HPP_
208