Implements an abstract output page.
Showing
1 changed file
with
226 additions
and
0 deletions
mail/page.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2005 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils 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 | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Mailutils; if not, write to the Free Software | ||
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
17 | MA 02110-1301 USA */ | ||
18 | |||
19 | #include "mail.h" | ||
20 | |||
21 | size_t top_of_page = 1; /* Number of the topmost message on the page */ | ||
22 | size_t cursor; /* Number of current message */ | ||
23 | |||
24 | size_t *page_map; /* Array of message numbers. page_map[N] holds | ||
25 | number of the message occupying Nth line on | ||
26 | the screen */ | ||
27 | unsigned page_size; /* Capacity of page_map */ | ||
28 | unsigned page_avail; /* First non-used entry in page map. Can be | ||
29 | equal to page_size */ | ||
30 | |||
31 | /* Auxiliary function: Store number of message from mspec into page_map */ | ||
32 | static int | ||
33 | _fill_map (msgset_t *mspec, message_t msg, void *data) | ||
34 | { | ||
35 | unsigned *pos = data; | ||
36 | page_map[*pos] = mspec->msg_part[0]; | ||
37 | ++*pos; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | /* Fill page_map. | ||
42 | page_avail must be set to zero before calling this function */ | ||
43 | static void | ||
44 | fill_page_map () | ||
45 | { | ||
46 | util_range_msg (top_of_page, page_size, | ||
47 | MSG_COUNT|MSG_NODELETED|MSG_SILENT, _fill_map, | ||
48 | &page_avail); | ||
49 | } | ||
50 | |||
51 | /* Check if the page_map is valid. If not, fill it. | ||
52 | Page_avail can be set to zero to force re-filling page_map. In particular | ||
53 | this happens when deleting current message or when SIGWINCH is delivered | ||
54 | to the program */ | ||
55 | static void | ||
56 | check_page_map () | ||
57 | { | ||
58 | if (!page_map) | ||
59 | { | ||
60 | page_size = util_screen_lines (); | ||
61 | page_map = xrealloc (page_map, sizeof (page_map[0]) * page_size); | ||
62 | page_avail = 0; | ||
63 | } | ||
64 | if (page_avail == 0) | ||
65 | fill_page_map (); | ||
66 | } | ||
67 | |||
68 | /* Invalidate page_map. HARD=1 means 'hard invalidation', implying | ||
69 | the need to reallocate the array */ | ||
70 | void | ||
71 | page_invalidate (int hard) | ||
72 | { | ||
73 | page_avail = 0; | ||
74 | if (hard) | ||
75 | { | ||
76 | free (page_map); | ||
77 | page_map = NULL; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | /* Invalidate page_map if VALUE is number of the current message */ | ||
82 | void | ||
83 | cond_page_invalidate (size_t value) | ||
84 | { | ||
85 | unsigned i; | ||
86 | |||
87 | if (page_map == NULL || page_avail == 0) | ||
88 | return; | ||
89 | for (i = 0; i < page_avail-1; i++) | ||
90 | if (page_map[i] >= value && value <= page_map[i+1]) | ||
91 | { | ||
92 | page_invalidate (0); | ||
93 | return; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | /* Return a 1-based index of page_map entry occupied by number VALUE. | ||
98 | Return 0 if VALUE is not found in page_map */ | ||
99 | static int | ||
100 | page_line (size_t value) | ||
101 | { | ||
102 | unsigned i; | ||
103 | |||
104 | for (i = 0; i < page_avail; i++) | ||
105 | if (page_map[i] == value) | ||
106 | return i+1; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | /* Return number of the current message. | ||
111 | Zero is returned if page_map is empty (i.e. mailbox is empy) */ | ||
112 | size_t | ||
113 | get_cursor () | ||
114 | { | ||
115 | check_page_map (); | ||
116 | if (page_avail == 0) | ||
117 | return 0; | ||
118 | return page_map[cursor]; | ||
119 | } | ||
120 | |||
121 | /* Move cursor to message number VALUE */ | ||
122 | void | ||
123 | set_cursor (unsigned value) | ||
124 | { | ||
125 | int n; | ||
126 | |||
127 | if (total == 0) | ||
128 | { | ||
129 | cursor = 0; | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | check_page_map (); | ||
134 | n = page_line (value); | ||
135 | if (n == 0) | ||
136 | { | ||
137 | top_of_page = value; | ||
138 | cursor = 0; | ||
139 | page_avail = 0; | ||
140 | fill_page_map (); | ||
141 | } | ||
142 | else | ||
143 | cursor = n - 1; | ||
144 | } | ||
145 | |||
146 | /* Return T if the cursor points to message number N */ | ||
147 | int | ||
148 | is_current_message (size_t n) | ||
149 | { | ||
150 | check_page_map (); | ||
151 | return page_map[cursor] == n; | ||
152 | } | ||
153 | |||
154 | /* Apply function FUNC to each message from the page. DATA supplies | ||
155 | call-specific data to the function. */ | ||
156 | void | ||
157 | page_do (msg_handler_t func, void *data) | ||
158 | { | ||
159 | unsigned i; | ||
160 | |||
161 | check_page_map (); | ||
162 | for (i = 0; i < page_avail; i++) | ||
163 | { | ||
164 | message_t msg; | ||
165 | msgset_t set; | ||
166 | |||
167 | set.next = NULL; | ||
168 | set.npart = 1; | ||
169 | set.msg_part = page_map + i; | ||
170 | mailbox_get_message (mbox, page_map[i], &msg); | ||
171 | func (&set, msg, data); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | /* Move current page OFFSET lines forward, if OFFSET > 0, or backward, | ||
176 | if OFFSET < 0. | ||
177 | Return number of items that will be displayed */ | ||
178 | size_t | ||
179 | page_move (off_t offset) | ||
180 | { | ||
181 | unsigned n; | ||
182 | size_t start; | ||
183 | size_t count = 0; | ||
184 | |||
185 | check_page_map (); | ||
186 | |||
187 | if (offset > 0) | ||
188 | start = page_map[cursor] + offset; | ||
189 | else if (-offset > page_map[cursor]) | ||
190 | start = 1; | ||
191 | else | ||
192 | start = page_map[cursor] + offset; | ||
193 | |||
194 | util_range_msg (start, page_size, | ||
195 | MSG_COUNT|MSG_NODELETED|MSG_SILENT, _fill_map, &count); | ||
196 | |||
197 | if (offset < 0 && top_of_page == page_map[0]) | ||
198 | { | ||
199 | page_avail = count; | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | if (count) | ||
204 | { | ||
205 | top_of_page = page_map[0]; | ||
206 | |||
207 | if (count < page_size && top_of_page > 1) | ||
208 | { | ||
209 | for (start = top_of_page - 1; count < page_size && start > 1; | ||
210 | start--) | ||
211 | { | ||
212 | if (!util_isdeleted (start)) | ||
213 | { | ||
214 | top_of_page = start; | ||
215 | cursor++; | ||
216 | count++; | ||
217 | } | ||
218 | } | ||
219 | page_avail = 0; | ||
220 | fill_page_map (); | ||
221 | } | ||
222 | else | ||
223 | page_avail = count; | ||
224 | } | ||
225 | return count; | ||
226 | } |
-
Please register or sign in to post a comment