Remove unnecessary locale/UTF-8 encoding conversions
[xonotic/netradiant.git] / radiant / mru.cpp
1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "mru.h"
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <gtk/gtklabel.h>
27
28 #include "os/file.h"
29 #include "generic/callback.h"
30 #include "stream/stringstream.h"
31 #include "convert.h"
32
33 #include "gtkutil/menu.h"
34 #include "map.h"
35 #include "qe3.h"
36
37 #define MRU_MAX 4
38 namespace {
39   GtkMenuItem *MRU_items[MRU_MAX];
40   std::size_t MRU_used;
41   typedef CopiedString MRU_filename_t;
42   MRU_filename_t MRU_filenames[MRU_MAX];
43   typedef const char* MRU_key_t;
44   MRU_key_t MRU_keys[MRU_MAX] = { "File0", "File1", "File2", "File3" };
45 }
46
47 inline const char* MRU_GetText(std::size_t index)
48 {
49   return MRU_filenames[index].c_str();
50 }
51
52 class EscapedMnemonic
53 {
54   StringBuffer m_buffer;
55 public:
56   EscapedMnemonic(std::size_t capacity) : m_buffer(capacity)
57   {
58     m_buffer.push_back('_');
59   }
60   const char* c_str() const
61   {
62     return m_buffer.c_str();
63   }
64   void push_back(char c) // not escaped
65   {
66     m_buffer.push_back(c);
67   }
68   std::size_t write(const char* buffer, std::size_t length)
69   {
70     for(const char* end = buffer + length; buffer != end; ++buffer)
71     {
72       if(*buffer == '_')
73       {
74         m_buffer.push_back('_');
75       }
76
77       m_buffer.push_back(*buffer);
78     }
79     return length;
80   }
81 };
82
83 template<typename T>
84 inline EscapedMnemonic& operator<<(EscapedMnemonic& ostream, const T& t)
85 {
86   return ostream_write(ostream, t);
87 }
88
89
90 void MRU_updateWidget(std::size_t index, const char *filename)
91 {
92   EscapedMnemonic mnemonic(64);
93   mnemonic << Unsigned(index + 1) << "- " << filename;
94   gtk_label_set_text_with_mnemonic(GTK_LABEL(gtk_bin_get_child(GTK_BIN(MRU_items[index]))), mnemonic.c_str());
95 }
96
97 void MRU_SetText(std::size_t index, const char *filename)
98 {
99   MRU_filenames[index] = filename;
100   MRU_updateWidget(index, filename);
101 }
102
103 void MRU_AddFile (const char *str)
104 {
105   std::size_t i;
106   const char* text;
107
108   // check if file is already in our list
109   for (i = 0; i < MRU_used; i++)
110   {
111     text = MRU_GetText (i);
112
113     if (strcmp (text, str) == 0)
114     {
115       // reorder menu
116       for(; i > 0; i--)
117               MRU_SetText(i, MRU_GetText (i-1));
118
119       MRU_SetText(0, str);
120
121       return;
122     }
123   }
124
125   if (MRU_used < MRU_MAX)
126     MRU_used++;
127
128   // move items down
129   for (i = MRU_used-1; i > 0; i--)
130     MRU_SetText (i, MRU_GetText (i-1));
131
132   MRU_SetText (0, str);
133   gtk_widget_set_sensitive(GTK_WIDGET(MRU_items[0]), TRUE);
134   gtk_widget_show(GTK_WIDGET(MRU_items[MRU_used-1]));
135 }
136
137 void MRU_Init()
138 {
139   if(MRU_used > MRU_MAX)
140     MRU_used = MRU_MAX;
141 }
142
143 void MRU_AddWidget(GtkMenuItem *widget, std::size_t pos)
144 {
145   if(pos < MRU_MAX)
146   {
147     MRU_items[pos] = widget;
148     if(pos < MRU_used)
149     {
150       MRU_updateWidget(pos, MRU_GetText(pos));
151       gtk_widget_set_sensitive(GTK_WIDGET(MRU_items[0]), TRUE);
152       gtk_widget_show(GTK_WIDGET(MRU_items[pos]));
153     }
154   }
155 }
156
157 void MRU_Activate (std::size_t index)
158 {
159   char text[1024];
160   strcpy(text, MRU_GetText(index));
161
162   if (file_readable(text)) //\todo Test 'map load succeeds' instead of 'file is readable'.
163   {
164     MRU_AddFile (text);
165     Map_RegionOff();
166     Map_Free();
167     Map_LoadFile (text);
168   }
169   else
170   {
171     MRU_used--;
172
173     for (std::size_t i = index; i < MRU_used; i++)
174       MRU_SetText (i, MRU_GetText (i+1));
175
176     if (MRU_used == 0)
177     {
178       gtk_label_set_text(GTK_LABEL(GTK_BIN(MRU_items[0])->child), "Recent Files");
179       gtk_widget_set_sensitive(GTK_WIDGET(MRU_items[0]), FALSE);
180     }
181     else
182     {
183       gtk_widget_hide(GTK_WIDGET(MRU_items[MRU_used]));
184     }
185   }
186 }
187
188
189 class LoadMRU
190 {
191   std::size_t m_number;
192 public:
193   LoadMRU(std::size_t number)
194     : m_number(number)
195   {
196   }
197   void load()
198   {
199     if (ConfirmModified("Open Map"))
200     {
201       MRU_Activate(m_number - 1);
202     }
203   }
204 };
205
206 typedef MemberCaller<LoadMRU, &LoadMRU::load> LoadMRUCaller;
207
208 LoadMRU g_load_mru1(1);
209 LoadMRU g_load_mru2(2);
210 LoadMRU g_load_mru3(3);
211 LoadMRU g_load_mru4(4);
212
213 void MRU_constructMenu(GtkMenu* menu)
214 {
215   {
216     GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "_1", LoadMRUCaller(g_load_mru1));
217     gtk_widget_set_sensitive(GTK_WIDGET(item), FALSE);
218     MRU_AddWidget(item, 0);
219   }
220   {
221     GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "_2", LoadMRUCaller(g_load_mru2));
222     gtk_widget_hide(GTK_WIDGET(item));
223     MRU_AddWidget(item, 1);
224   }
225   {
226     GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "_3", LoadMRUCaller(g_load_mru3));
227     gtk_widget_hide(GTK_WIDGET(item));
228     MRU_AddWidget(item, 2);
229   }
230   {
231     GtkMenuItem* item = create_menu_item_with_mnemonic(menu, "_4", LoadMRUCaller(g_load_mru4));
232     gtk_widget_hide(GTK_WIDGET(item));
233     MRU_AddWidget(item, 3);
234   }
235 }
236
237 #include "preferencesystem.h"
238 #include "stringio.h"
239
240 void MRU_Construct()
241 {
242   GlobalPreferenceSystem().registerPreference("Count", SizeImportStringCaller(MRU_used), SizeExportStringCaller(MRU_used));
243   
244   for(std::size_t i = 0; i != MRU_MAX; ++i)
245   {
246     GlobalPreferenceSystem().registerPreference(MRU_keys[i], CopiedStringImportStringCaller(MRU_filenames[i]), CopiedStringExportStringCaller(MRU_filenames[i]));
247   }
248
249   MRU_Init();
250 }
251 void MRU_Destroy()
252 {
253 }