@@ -3,9 +3,8 @@ use crate::message_prelude::*;
3
3
use graphene:: layers:: Layer ;
4
4
use graphene:: { LayerId , Operation as DocumentOperation } ;
5
5
use log:: warn;
6
-
7
6
use serde:: { Deserialize , Serialize } ;
8
- use std:: collections:: VecDeque ;
7
+ use std:: collections:: { HashMap , VecDeque } ;
9
8
10
9
use super :: DocumentMessageHandler ;
11
10
use crate :: consts:: DEFAULT_DOCUMENT_NAME ;
@@ -36,28 +35,37 @@ pub enum DocumentsMessage {
36
35
37
36
#[ derive( Debug , Clone ) ]
38
37
pub struct DocumentsMessageHandler {
39
- documents : Vec < DocumentMessageHandler > ,
38
+ documents : HashMap < u64 , DocumentMessageHandler > ,
39
+ document_ids : Vec < u64 > ,
40
+ document_id_counter : u64 ,
40
41
active_document_index : usize ,
41
42
copy_buffer : Vec < Layer > ,
42
43
}
43
44
44
45
impl DocumentsMessageHandler {
45
46
pub fn active_document ( & self ) -> & DocumentMessageHandler {
46
- & self . documents [ self . active_document_index ]
47
+ let id = self . document_ids [ self . active_document_index ] ;
48
+ self . documents . get ( & id) . unwrap ( )
47
49
}
50
+
48
51
pub fn active_document_mut ( & mut self ) -> & mut DocumentMessageHandler {
49
- & mut self . documents [ self . active_document_index ]
52
+ let id = self . document_ids [ self . active_document_index ] ;
53
+ self . documents . get_mut ( & id) . unwrap ( )
50
54
}
55
+
51
56
fn generate_new_document_name ( & self ) -> String {
52
57
let mut doc_title_numbers = self
53
- . documents
58
+ . document_ids
54
59
. iter ( )
55
- . filter_map ( |d| {
56
- d. name
60
+ . filter_map ( |id| self . documents . get ( & id) )
61
+ . map ( |doc| {
62
+ doc. name
57
63
. rsplit_once ( DEFAULT_DOCUMENT_NAME )
58
64
. map ( |( prefix, number) | ( prefix. is_empty ( ) ) . then ( || number. trim ( ) . parse :: < isize > ( ) . ok ( ) ) . flatten ( ) . unwrap_or ( 1 ) )
65
+ . unwrap ( )
59
66
} )
60
67
. collect :: < Vec < isize > > ( ) ;
68
+
61
69
doc_title_numbers. sort_unstable ( ) ;
62
70
doc_title_numbers. iter_mut ( ) . enumerate ( ) . for_each ( |( i, number) | * number = * number - i as isize - 2 ) ;
63
71
// Uses binary search to find the index of the element where number is bigger than i
@@ -71,11 +79,14 @@ impl DocumentsMessageHandler {
71
79
}
72
80
73
81
fn load_document ( & mut self , new_document : DocumentMessageHandler , responses : & mut VecDeque < Message > ) {
74
- self . active_document_index = self . documents . len ( ) ;
75
- self . documents . push ( new_document) ;
82
+ self . document_id_counter += 1 ;
83
+ self . active_document_index = self . document_ids . len ( ) ;
84
+ self . document_ids . push ( self . document_id_counter ) ;
85
+ self . documents . insert ( self . document_id_counter , new_document) ;
76
86
77
87
// Send the new list of document tab names
78
- let open_documents = self . documents . iter ( ) . map ( |doc| doc. name . clone ( ) ) . collect ( ) ;
88
+ let open_documents = self . document_ids . iter ( ) . filter_map ( |id| self . documents . get ( & id) . map ( |doc| doc. name . clone ( ) ) ) . collect :: < Vec < String > > ( ) ;
89
+
79
90
responses. push_back ( FrontendMessage :: UpdateOpenDocumentsList { open_documents } . into ( ) ) ;
80
91
81
92
responses. push_back ( DocumentsMessage :: SelectDocument ( self . active_document_index ) . into ( ) ) ;
@@ -89,10 +100,14 @@ impl DocumentsMessageHandler {
89
100
90
101
impl Default for DocumentsMessageHandler {
91
102
fn default ( ) -> Self {
103
+ let mut documents_map: HashMap < u64 , DocumentMessageHandler > = HashMap :: with_capacity ( 1 ) ;
104
+ documents_map. insert ( 0 , DocumentMessageHandler :: default ( ) ) ;
92
105
Self {
93
- documents : vec ! [ DocumentMessageHandler :: default ( ) ] ,
94
- active_document_index : 0 ,
106
+ documents : documents_map ,
107
+ document_ids : vec ! [ 0 ] ,
95
108
copy_buffer : vec ! [ ] ,
109
+ active_document_index : 0 ,
110
+ document_id_counter : 0 ,
96
111
}
97
112
}
98
113
}
@@ -103,15 +118,11 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
103
118
use DocumentsMessage :: * ;
104
119
match message {
105
120
Document ( message) => self . active_document_mut ( ) . process_action ( message, ipp, responses) ,
106
- SelectDocument ( id) => {
107
- assert ! ( id < self . documents. len( ) , "Tried to select a document that was not initialized" ) ;
108
- self . active_document_index = id;
109
- responses. push_back (
110
- FrontendMessage :: SetActiveDocument {
111
- document_index : self . active_document_index ,
112
- }
113
- . into ( ) ,
114
- ) ;
121
+ SelectDocument ( index) => {
122
+ // NOTE: Potentially this will break if we ever exceed 56 bit values due to how the message parsing system works.
123
+ assert ! ( index < self . documents. len( ) , "Tried to select a document that was not initialized" ) ;
124
+ self . active_document_index = index;
125
+ responses. push_back ( FrontendMessage :: SetActiveDocument { document_index : index } . into ( ) ) ;
115
126
responses. push_back ( RenderDocument . into ( ) ) ;
116
127
responses. push_back ( DocumentMessage :: DocumentStructureChanged . into ( ) ) ;
117
128
for layer in self . active_document ( ) . layer_data . keys ( ) {
@@ -132,54 +143,47 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
132
143
CloseAllDocuments => {
133
144
// Empty the list of internal document data
134
145
self . documents . clear ( ) ;
146
+ self . document_ids . clear ( ) ;
135
147
136
148
// Create a new blank document
137
149
responses. push_back ( NewDocument . into ( ) ) ;
138
150
}
139
- CloseDocument ( id) => {
140
- assert ! ( id < self . documents. len( ) , "Tried to select a document that was not initialized" ) ;
141
- // Remove doc from the backend store; use `id` as client tabs and backend documents will be in sync
142
- self . documents . remove ( id) ;
143
-
144
- // Send the new list of document tab names
145
- let open_documents = self . documents . iter ( ) . map ( |doc| doc. name . clone ( ) ) . collect ( ) ;
146
- responses. push_back ( FrontendMessage :: UpdateOpenDocumentsList { open_documents } . into ( ) ) ;
151
+ CloseDocument ( index) => {
152
+ assert ! ( index < self . documents. len( ) , "Tried to close a document that was not initialized" ) ;
153
+ // Get the ID based on the current collection of the documents.
154
+ let id = self . document_ids [ index] ;
155
+ // Map the ID to an index and remove the document
156
+ self . documents . remove ( & id) ;
157
+ self . document_ids . remove ( index) ;
147
158
148
159
// Last tab was closed, so create a new blank tab
149
- if self . documents . is_empty ( ) {
150
- self . active_document_index = 0 ;
151
- responses. push_back ( NewDocument . into ( ) ) ;
160
+ if self . document_ids . is_empty ( ) {
161
+ self . document_id_counter += 1 ;
162
+ self . document_ids . push ( self . document_id_counter ) ;
163
+ self . documents . insert ( self . document_id_counter , DocumentMessageHandler :: default ( ) ) ;
152
164
}
153
- // The currently selected doc is being closed
154
- else if id == self . active_document_index {
155
- // The currently selected tab was the rightmost tab
156
- if id == self . documents . len ( ) {
157
- self . active_document_index -= 1 ;
158
- }
159
165
160
- responses. push_back ( DocumentMessage :: DocumentStructureChanged . into ( ) ) ;
161
- responses. push_back (
162
- FrontendMessage :: SetActiveDocument {
163
- document_index : self . active_document_index ,
164
- }
165
- . into ( ) ,
166
- ) ;
167
- responses. push_back (
168
- FrontendMessage :: UpdateCanvas {
169
- document : self . active_document_mut ( ) . graphene_document . render_root ( ) ,
170
- }
171
- . into ( ) ,
172
- ) ;
173
- }
174
- // Active doc will move one space to the left
175
- else if id < self . active_document_index {
176
- self . active_document_index -= 1 ;
177
- responses. push_back (
178
- FrontendMessage :: SetActiveDocument {
179
- document_index : self . active_document_index ,
180
- }
181
- . into ( ) ,
182
- ) ;
166
+ self . active_document_index = if self . active_document_index >= self . document_ids . len ( ) {
167
+ self . document_ids . len ( ) - 1
168
+ } else {
169
+ index
170
+ } ;
171
+
172
+ // Send the new list of document tab names
173
+ let open_documents = self . document_ids . iter ( ) . filter_map ( |id| self . documents . get ( & id) . map ( |doc| doc. name . clone ( ) ) ) . collect ( ) ;
174
+
175
+ // Update the list of new documents on the front end, active tab, and ensure that document renders
176
+ responses. push_back ( FrontendMessage :: UpdateOpenDocumentsList { open_documents } . into ( ) ) ;
177
+ responses. push_back (
178
+ FrontendMessage :: SetActiveDocument {
179
+ document_index : self . active_document_index ,
180
+ }
181
+ . into ( ) ,
182
+ ) ;
183
+ responses. push_back ( RenderDocument . into ( ) ) ;
184
+ responses. push_back ( DocumentMessage :: DocumentStructureChanged . into ( ) ) ;
185
+ for layer in self . active_document ( ) . layer_data . keys ( ) {
186
+ responses. push_back ( DocumentMessage :: LayerChanged ( layer. clone ( ) ) . into ( ) ) ;
183
187
}
184
188
}
185
189
NewDocument => {
@@ -207,16 +211,17 @@ impl MessageHandler<DocumentsMessage, &InputPreprocessor> for DocumentsMessageHa
207
211
}
208
212
GetOpenDocumentsList => {
209
213
// Send the list of document tab names
210
- let open_documents = self . documents . iter ( ) . map ( |doc| doc. name . clone ( ) ) . collect ( ) ;
214
+ let open_documents = self . documents . values ( ) . map ( |doc| doc. name . clone ( ) ) . collect ( ) ;
211
215
responses. push_back ( FrontendMessage :: UpdateOpenDocumentsList { open_documents } . into ( ) ) ;
212
216
}
213
217
NextDocument => {
214
- let id = ( self . active_document_index + 1 ) % self . documents . len ( ) ;
215
- responses. push_back ( SelectDocument ( id ) . into ( ) ) ;
218
+ let next = ( self . active_document_index + 1 ) % self . document_ids . len ( ) ;
219
+ responses. push_back ( SelectDocument ( next ) . into ( ) ) ;
216
220
}
217
221
PrevDocument => {
218
- let id = ( self . active_document_index + self . documents . len ( ) - 1 ) % self . documents . len ( ) ;
219
- responses. push_back ( SelectDocument ( id) . into ( ) ) ;
222
+ let len = self . document_ids . len ( ) ;
223
+ let prev = ( self . active_document_index + len - 1 ) % len;
224
+ responses. push_back ( SelectDocument ( prev) . into ( ) ) ;
220
225
}
221
226
Copy => {
222
227
let paths = self . active_document ( ) . selected_layers_sorted ( ) ;
0 commit comments