Commit 416b243f 416b243f9898b821fc8b86008ab02181977272e1 by Sergey Poznyakoff

Implements an abstract output page.

1 parent 5e5ad1bb
Showing 1 changed file with 226 additions and 0 deletions
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 }