Subversion Repositories Filer-Free

Rev

Rev 31 | Rev 33 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
31 gdshaw@RISCPKG.ORG 1
// This file is part of the free Filer module for RISC OS.
2
// Copyright  2007 Graham Shaw.
3
// Redistribution and modification are permitted under the terms of the
4
// GNU General Public License (version 2 or any later version).
5
 
6
#include <cstring>
7
#include <cstdio>
8
 
9
#include "oslib/fileraction.h"
10
#include "oslib/osfscontrol.h"
11
 
12
#include "filer_options.h"
13
#include "filer_window.h"
14
#include "filer_menu.h"
15
 
16
namespace {
17
 
18
/** The maximum length of a leafname. */
19
const size_t max_name_length=256;
20
 
21
}; /* anonymous namespace */
22
 
23
filer_menu::filer_menu(application* app):
24
        menu(app,"Filer",9),
25
        _owner(0),
26
        _object(0),
27
        _display_menu(app,"Display",8),
28
        _rename_menu(app,"Rename",1),
29
        _access_menu(app,"Access",5),
30
        _find_menu(app,"Find",1),
31
        _filetype_menu(app,"Set type",1),
32
        _selection_menu(app,"File",11),
33
        _options_menu(app,"Options",6),
34
        _rename_leafname(0),
35
        _find_pattern(0),
36
        _filetype_field(0),
37
        _selection_text(new char[12+max_name_length]),
38
        _layout_count(3),
39
        _layout_methods(new layout_method*[_layout_count]),
40
        _sort_count(4),
41
        _sort_methods(new sort_method*[_sort_count])
42
{
43
        _layout_methods[0]=&filer_options::layout_large();
44
        _layout_methods[1]=&filer_options::layout_small();
45
        _layout_methods[2]=&filer_options::layout_full();
46
 
47
        _sort_methods[0]=&filer_options::sort_by_name();
48
        _sort_methods[1]=&filer_options::sort_by_type();
49
        _sort_methods[2]=&filer_options::sort_by_size();
50
        _sort_methods[3]=&filer_options::sort_by_date();
51
 
52
        _display_menu[0].text("Large icons");
53
        _display_menu[1].text("Small icons");
54
        _display_menu[2].text("Full info");
55
        _display_menu[3].text("Thumbnails");
56
        _display_menu[4].text("Sort by name");
57
        _display_menu[5].text("Sort by type");
58
        _display_menu[6].text("Sort by size");
59
        _display_menu[7].text("Sort by date");
60
        _display_menu[3].separator(1);
61
 
62
        _rename_leafname=new char[256];
63
        _rename_leafname[0]=0;
64
        _rename_menu[0].text(_rename_leafname,256);
65
        _rename_menu[0].writable(1);
66
 
67
        _access_menu[0].text("Protected");
68
        _access_menu[1].text("Unprotected");
69
        _access_menu[2].text("Public");
70
        _access_menu[3].text("Private");
71
        _access_menu[4].text("Access details");
72
        _access_menu[1].separator(1);
73
        _access_menu[3].separator(1);
74
 
75
        _find_pattern=new char[256];
76
        _find_pattern[0]=0;
77
        _find_menu[0].text(_find_pattern,256);
78
        _find_menu[0].writable(1);
79
 
80
        _filetype_field=new char[16];
81
        _filetype_field[0]=0;
82
        _filetype_menu[0].text(_filetype_field,16);
83
        _filetype_menu[0].writable(1);
84
 
85
        _selection_menu[0].text("Copy");
86
        _selection_menu[1].text("Rename");
87
        _selection_menu[2].text("Delete");
88
        _selection_menu[3].text("Access");
89
        _selection_menu[4].text("Count");
90
        _selection_menu[5].text("Help");
91
        _selection_menu[6].text("Info");
92
        _selection_menu[7].text("Find");
93
        _selection_menu[8].text("Set type");
94
        _selection_menu[9].text("Stamp");
95
        _selection_menu[10].text("Share");
96
        _selection_menu[1].submenu(_rename_menu);
97
        _selection_menu[3].submenu(_access_menu);
98
        _selection_menu[7].submenu(_find_menu);
99
        _selection_menu[8].submenu(_filetype_menu);
100
 
101
        _options_menu[0].text("Confirm all");
102
        _options_menu[1].text("Confirm deletes");
103
        _options_menu[2].text("Verbose");
104
        _options_menu[3].text("Force");
105
        _options_menu[4].text("Newer");
106
        _options_menu[5].text("Faster");
107
        _options_menu[1].separator(1);
108
 
109
        *_selection_text=0;
110
        (*this)[0].text("Display");
111
        (*this)[1].text(_selection_text);
112
        (*this)[2].text("Select all");
113
        (*this)[3].text("Clear selection");
114
        (*this)[4].text("Options");
115
        (*this)[5].text("New directory");
116
        (*this)[6].text("Set work directory");
117
        (*this)[7].text("Open parent");
118
        (*this)[8].text("Refresh");
119
        (*this)[0].submenu(_display_menu);
120
        (*this)[1].submenu(_selection_menu);
121
        (*this)[4].submenu(_options_menu);
122
}
123
 
124
filer_menu::~filer_menu()
125
{
126
        delete[] _rename_leafname;
127
        delete[] _find_pattern;
128
        delete[] _filetype_field;
129
        delete[] _selection_text;
130
        delete[] _layout_methods;
131
        delete[] _sort_methods;
132
}
133
 
134
void filer_menu::handle_menu_selection(wimp_selection& block)
135
{
136
        // Ensure that handler can never be executed when the menu
137
        // has no owner.
138
        if (!_owner) return;
139
 
140
        // Get mouse button state for later use.
141
        // (Do this at an early stage in case it changes.)
142
        wimp_pointer info;
143
        xwimp_get_pointer_info(&info);
144
 
32 gdshaw@RISCPKG.ORG 145
        switch (block.items[0])
146
        {
147
        case 2:
148
                _owner->select_all(1);
149
                break;
150
        case 3:
151
                _owner->select_all(0);
152
                break;
153
        }
154
 
31 gdshaw@RISCPKG.ORG 155
        if (info.buttons&1)
156
        {
157
                // If selection made with adjust click then re-open menu.
158
                menu::show(info);
159
        }
160
        else
161
        {
162
                // Otherwise, allow menu to close but inform filer window.
163
                if (_owner) _owner->handle_menus_deleted();
164
        }
165
}
166
 
167
void filer_menu::handle_menus_deleted()
168
{
169
        // If menu is closed, other than because of a selection, then
170
        // inform filer window.
171
        if (_owner) _owner->handle_menus_deleted();
172
}
173
 
174
void filer_menu::show(wimp_pointer& block)
175
{
176
        menu::show(block);
177
}
178
 
179
void filer_menu::update_layout()
180
{
181
        // Iterate over the list of layout methods.
182
        // Tick the one which matches the window, untick the others.
183
        layout_method& method=_owner->options().layout();
184
        for (unsigned int i=0;i!=_layout_count;++i)
185
                _display_menu[i].tick(_layout_methods[i]==&method);
186
}
187
 
188
void filer_menu::update_sort()
189
{
190
        sort_method& method=_owner->options().sort();
191
        for (unsigned int i=0;i!=_sort_count;++i)
192
                _display_menu[4+i].tick(_sort_methods[i]==&method);
193
}
194
 
195
void filer_menu::update_selection()
196
{
197
        // Fetch selection and temporary selection.
198
        directory& objects=_owner->selection();
199
        unsigned int temp_selection=_owner->temp_selection();
200
 
201
        // Iterate over selection, counting objects and distinct filetypes
202
        // (in the latter case, distinguishing only between 0, 1 and some).
203
        // If there is only one selected object then record its identity.
204
        // Similarly if there is only one distinct filetype.
205
        osgbpb_info* object=0;
206
        unsigned int count=0;
207
        bits filetype_last=(bits)-1;
208
        int filetype_count=0;
209
        for (int i=0,i_end=objects.size();i!=i_end;++i)
210
        {
211
                if (objects[i].selected())
212
                {
213
                        // Count selected objects.
214
                        osgbpb_info& info=*objects[i];
215
                        switch (info.obj_type)
216
                        {
217
                        case fileswitch_IS_FILE:
218
                        case fileswitch_IS_DIR:
219
                        case fileswitch_IS_IMAGE:
220
                                object=&info;
221
                                ++count;
222
                                break;
223
                        }
224
 
225
                        // Count distinct filetypes.
226
                        // In fact what is recorded is the number of times the filetype
227
                        // changes whilst iterating through the selection, which is
228
                        // useful enough but easier to compute.
229
                        bits filetype=(bits)-1;
230
                        xosfscontrol_info_to_file_type(info.name,info.load_addr,
231
                                info.exec_addr,info.size,info.attr,info.obj_type,&filetype);
232
                        if (filetype!=filetype_last)
233
                        {
234
                                filetype_last=filetype;
235
                                ++filetype_count;
236
                        }
237
                }
238
        }
239
 
240
        // Determine how many objects were counted because they are part of
241
        // a temporary selection.  (This will be either 0 or 1.)
242
        unsigned int temp_count=0;
243
        if ((temp_selection!=directory::npos)&&
244
                (objects[temp_selection].selected())) ++temp_count;
245
 
246
        // Update text of menu entry leading to selection submenu.
247
        if (count==0)
248
        {
249
                // No objects selected.
250
                _object=0;
251
                std::sprintf(_selection_text,"File ''");
252
        }
253
        else if (count==1)
254
        {
255
                // One object selected.
256
                // Text depends on whether it is a file, directory, image file,
257
                // or application directory.
258
                _object=object;
259
                const char* fmt="";
260
                switch (object->obj_type)
261
                {
262
                case fileswitch_IS_FILE:
263
                        fmt="File '%.*s'";
264
                        break;
265
                case fileswitch_IS_IMAGE:
266
                        if (object->name[0]=='!') fmt="App. '%.*s'";
267
                        else fmt="Image '%.*s'";
268
                        break;
269
                case fileswitch_IS_DIR:
270
                        if (object->name[0]=='!') fmt="App. '%.*s'";
271
                        else fmt="Dir. '%.*s'";
272
                        break;
273
                }
274
                std::sprintf(_selection_text,fmt,max_name_length,object->name);
275
        }
276
        else
277
        {
278
                // More than one object selected.
279
                _object=0;
280
                std::sprintf(_selection_text,"Selection");
281
        }
282
 
283
        // Disable selection submenu if nothing selected.
284
        // Disable select all if everything already selected.
285
        // Disable clear selection if nothing selected.
286
        // (Disregard any temporary selection.)
287
        (*this)[1].disabled(count==0);
288
        (*this)[2].disabled(count-temp_count==objects.size());
289
        (*this)[3].disabled(count-temp_count==0);
290
 
291
        // Disable copy and rename options unless exactly one object selected.
292
        _selection_menu[0].disabled(count!=1);
293
        _selection_menu[1].disabled(count!=1);
294
 
295
        // Disable help option unless exactly one application selected.
296
        _selection_menu[5].disabled(!(count==1&&
297
                (object->obj_type&fileswitch_IS_DIR)&&object->name[0]=='!'));
298
 
299
        // Disable info option unless exactly one object selected.
300
        _selection_menu[6].disabled(count!=1);
301
 
302
        // Populate filetype field.
303
        if ((filetype_count==1)&&(filetype_last<0x1000))
304
        {
305
                union
306
                {
307
                        bits words[2];
308
                        char chars[9];
309
                };
310
                xosfscontrol_read_file_type(filetype_last,&words[0],&words[1]);
311
                int i=8;
312
                while (i&&chars[i-1]==' ') --i;
313
                chars[i]=0;
314
                std::strcpy(_filetype_field,chars);
315
        }
316
        else _filetype_field[0]=0;
317
}
318
 
319
void filer_menu::update_pathname()
320
{
321
        // Disable open parent option if already at root.
322
        char* pathname=(char*)_owner->pathname();
323
        char* lastdot=strrchr(pathname,'.');
324
        int isroot=!(lastdot&&strcmp(lastdot+1,"$"));
325
        (*this)[7].disabled(isroot);
326
}
327
 
328
void filer_menu::update(filer_window* owner)
329
{
330
        _owner=owner;
331
        if (_owner)
332
        {
333
                update_layout();
334
                update_sort();
335
                update_selection();
336
                update_pathname();
337
        }
338
}