btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / diskprobe / DiskProbe.cpp
blob3891fe373cbdb4948bca041e0ba7dbbdbecf1cfc
1 /*
2 * Copyright 2004-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "DiskProbe.h"
9 #include <stdio.h>
10 #include <string.h>
12 #include <AboutWindow.h>
13 #include <Alert.h>
14 #include <Application.h>
15 #include <Autolock.h>
16 #include <Catalog.h>
17 #include <Directory.h>
18 #include <Entry.h>
19 #include <FilePanel.h>
20 #include <FindDirectory.h>
21 #include <LayoutUtils.h>
22 #include <Locale.h>
23 #include <Path.h>
24 #include <Screen.h>
25 #include <TextView.h>
27 #include "DataEditor.h"
28 #include "DataView.h"
29 #include "FileWindow.h"
30 #include "AttributeWindow.h"
31 #include "OpenWindow.h"
32 #include "FindWindow.h"
35 #undef B_TRANSLATION_CONTEXT
36 #define B_TRANSLATION_CONTEXT "DiskProbe"
39 const char *kSignature = "application/x-vnd.Haiku-DiskProbe";
41 static const uint32 kMsgDiskProbeSettings = 'DPst';
42 static const uint32 kCascadeOffset = 20;
45 struct disk_probe_settings {
46 BRect window_frame;
47 int32 base_type;
48 int32 font_size;
49 int32 flags;
53 enum disk_probe_flags {
54 kCaseSensitive = 0x01, // this flag alone is R5 DiskProbe settings compatible
55 kHexFindMode = 0x02,
59 class Settings {
60 public:
61 Settings();
62 ~Settings();
64 const BMessage &Message() const { return fMessage; }
65 void UpdateFrom(BMessage *message);
67 private:
68 status_t Open(BFile *file, int32 mode);
70 BMessage fMessage;
71 bool fUpdated;
75 class DiskProbe : public BApplication {
76 public:
77 DiskProbe();
78 virtual ~DiskProbe();
80 virtual void ReadyToRun();
82 virtual void RefsReceived(BMessage *message);
83 virtual void ArgvReceived(int32 argc, char **argv);
84 virtual void MessageReceived(BMessage *message);
86 virtual bool QuitRequested();
88 private:
89 status_t Probe(BEntry &entry, const char *attribute = NULL);
91 Settings fSettings;
92 BFilePanel *fFilePanel;
93 BWindow *fOpenWindow;
94 FindWindow *fFindWindow;
95 uint32 fWindowCount;
96 BRect fWindowFrame;
97 BMessenger fFindTarget;
101 //-----------------
104 Settings::Settings()
106 fMessage(kMsgDiskProbeSettings),
107 fUpdated(false)
109 float fontSize = be_plain_font->Size();
110 int32 windowWidth = DataView::WidthForFontSize(fontSize) + 20;
111 // TODO: make scrollbar width variable
113 BScreen screen;
114 fMessage.AddRect("window_frame", BLayoutUtils::AlignInFrame(screen.Frame(),
115 BSize(windowWidth, windowWidth),
116 BAlignment(B_ALIGN_HORIZONTAL_CENTER, B_ALIGN_VERTICAL_CENTER)));
117 fMessage.AddInt32("base_type", kHexBase);
118 fMessage.AddFloat("font_size", fontSize);
119 fMessage.AddBool("case_sensitive", true);
120 fMessage.AddInt8("find_mode", kAsciiMode);
122 BFile file;
123 if (Open(&file, B_READ_ONLY) != B_OK)
124 return;
126 // ToDo: load/save settings as flattened BMessage - but not yet,
127 // since that will break compatibility with R5's DiskProbe
129 disk_probe_settings settings;
130 if (file.Read(&settings, sizeof(settings)) == sizeof(settings)) {
131 #if B_HOST_IS_BENDIAN
132 // settings are saved in little endian
133 settings.window_frame.left = B_LENDIAN_TO_HOST_FLOAT(
134 settings.window_frame.left);
135 settings.window_frame.top = B_LENDIAN_TO_HOST_FLOAT(
136 settings.window_frame.top);
137 settings.window_frame.right = B_LENDIAN_TO_HOST_FLOAT(
138 settings.window_frame.right);
139 settings.window_frame.bottom = B_LENDIAN_TO_HOST_FLOAT(
140 settings.window_frame.bottom);
141 #endif
142 // check if the window frame is on screen at all
143 BScreen screen;
144 if (screen.Frame().Contains(settings.window_frame.LeftTop())
145 && settings.window_frame.Width() < screen.Frame().Width()
146 && settings.window_frame.Height() < screen.Frame().Height())
147 fMessage.ReplaceRect("window_frame", settings.window_frame);
149 if (settings.base_type == kHexBase
150 || settings.base_type == kDecimalBase)
151 fMessage.ReplaceInt32("base_type",
152 B_LENDIAN_TO_HOST_INT32(settings.base_type));
153 if (settings.font_size >= 0 && settings.font_size <= 72)
154 fMessage.ReplaceFloat("font_size",
155 float(B_LENDIAN_TO_HOST_INT32(settings.font_size)));
157 fMessage.ReplaceBool("case_sensitive",
158 settings.flags & kCaseSensitive);
159 fMessage.ReplaceInt8("find_mode",
160 settings.flags & kHexFindMode ? kHexMode : kAsciiMode);
165 Settings::~Settings()
167 // only save the settings if something has changed
168 if (!fUpdated)
169 return;
171 BFile file;
172 if (Open(&file, B_CREATE_FILE | B_WRITE_ONLY) != B_OK)
173 return;
175 disk_probe_settings settings;
177 settings.window_frame = fMessage.FindRect("window_frame");
178 #if B_HOST_IS_BENDIAN
179 // settings are saved in little endian
180 settings.window_frame.left = B_HOST_TO_LENDIAN_FLOAT(
181 settings.window_frame.left);
182 settings.window_frame.top = B_HOST_TO_LENDIAN_FLOAT(
183 settings.window_frame.top);
184 settings.window_frame.right = B_HOST_TO_LENDIAN_FLOAT(
185 settings.window_frame.right);
186 settings.window_frame.bottom = B_HOST_TO_LENDIAN_FLOAT(
187 settings.window_frame.bottom);
188 #endif
190 settings.base_type = B_HOST_TO_LENDIAN_INT32(
191 fMessage.FindInt32("base_type"));
192 settings.font_size = B_HOST_TO_LENDIAN_INT32(
193 int32(fMessage.FindFloat("font_size") + 0.5f));
194 settings.flags = B_HOST_TO_LENDIAN_INT32(
195 (fMessage.FindBool("case_sensitive") ? kCaseSensitive : 0)
196 | (fMessage.FindInt8("find_mode") == kHexMode ? kHexFindMode : 0));
198 file.Write(&settings, sizeof(settings));
202 status_t
203 Settings::Open(BFile *file, int32 mode)
205 BPath path;
206 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
207 return B_ERROR;
209 path.Append("DiskProbe_data");
211 return file->SetTo(path.Path(), mode);
215 void
216 Settings::UpdateFrom(BMessage *message)
218 BRect frame;
219 if (message->FindRect("window_frame", &frame) == B_OK)
220 fMessage.ReplaceRect("window_frame", frame);
222 int32 baseType;
223 if (message->FindInt32("base_type", &baseType) == B_OK)
224 fMessage.ReplaceInt32("base_type", baseType);
226 float fontSize;
227 if (message->FindFloat("font_size", &fontSize) == B_OK)
228 fMessage.ReplaceFloat("font_size", fontSize);
230 bool caseSensitive;
231 if (message->FindBool("case_sensitive", &caseSensitive) == B_OK)
232 fMessage.ReplaceBool("case_sensitive", caseSensitive);
234 int8 findMode;
235 if (message->FindInt8("find_mode", &findMode) == B_OK)
236 fMessage.ReplaceInt8("find_mode", findMode);
238 fUpdated = true;
242 // #pragma mark -
245 DiskProbe::DiskProbe()
246 : BApplication(kSignature),
247 fOpenWindow(NULL),
248 fFindWindow(NULL),
249 fWindowCount(0)
251 fFilePanel = new BFilePanel();
252 fWindowFrame = fSettings.Message().FindRect("window_frame");
256 DiskProbe::~DiskProbe()
258 delete fFilePanel;
262 void
263 DiskProbe::ReadyToRun()
265 // are there already windows open?
266 if (CountWindows() != 1)
267 return;
269 // if not, ask the user to open a file
270 PostMessage(kMsgOpenOpenWindow);
274 /** Opens a window containing the file pointed to by the entry_ref.
275 * This function will fail if that file doesn't exist or could not
276 * be opened.
277 * It will check if there already is a window that probes the
278 * file in question and will activate it in that case.
279 * This function must be called with the application looper locked.
282 status_t
283 DiskProbe::Probe(BEntry &entry, const char *attribute)
285 entry_ref ref;
286 status_t status = entry.GetRef(&ref);
287 if (status < B_OK)
288 return status;
290 ProbeWindow *lastWindow(NULL);
292 // Do we already have that window open?
293 for (int32 i = CountWindows(); i-- > 0; ) {
294 ProbeWindow *window = dynamic_cast<ProbeWindow *>(WindowAt(i));
295 if (window == NULL)
296 continue;
298 if (window->Contains(ref, attribute)) {
299 window->Activate(true);
300 return B_OK;
302 if (lastWindow == NULL)
303 lastWindow = window;
306 // Does the file really exist?
307 if (!entry.Exists())
308 return B_ENTRY_NOT_FOUND;
310 entry.GetRef(&ref);
312 // cascade window
313 BRect rect;
314 if (lastWindow != NULL)
315 rect = lastWindow->Frame();
316 else
317 rect = fWindowFrame;
319 rect.OffsetBy(kCascadeOffset, kCascadeOffset);
321 BWindow *window;
322 if (attribute != NULL)
323 window = new AttributeWindow(rect, &ref, attribute, &fSettings.Message());
324 else
325 window = new FileWindow(rect, &ref, &fSettings.Message());
327 window->Show();
329 /* adjust the cascading... we can only do this after the window was created
330 * to adjust to the real size */
331 rect.right = window->Frame().right;
332 rect.bottom = window->Frame().bottom;
334 BScreen screen;
335 BRect screenBorder = screen.Frame();
337 float left = rect.left;
338 if (left + rect.Width() > screenBorder.right)
339 left = 7;
341 float top = rect.top;
342 if (top + rect.Height() > screenBorder.bottom)
343 top = 26;
345 rect.OffsetTo(BPoint(left, top));
346 window->MoveTo(BPoint(left, top));
348 fWindowCount++;
350 return B_OK;
354 void
355 DiskProbe::RefsReceived(BMessage *message)
357 bool traverseLinks = (modifiers() & B_SHIFT_KEY) == 0;
359 int32 index = 0;
360 entry_ref ref;
361 while (message->FindRef("refs", index++, &ref) == B_OK) {
362 const char *attribute = NULL;
363 if (message->FindString("attributes", index - 1, &attribute) == B_OK)
364 traverseLinks = false;
366 BEntry entry;
367 status_t status = entry.SetTo(&ref, traverseLinks);
369 if (status == B_OK)
370 status = Probe(entry, attribute);
372 if (status != B_OK) {
373 char buffer[1024];
374 snprintf(buffer, sizeof(buffer),
375 B_TRANSLATE_COMMENT("Could not open \"%s\":\n"
376 "%s", "Opening of entry reference buffer for a DiskProbe "
377 "request Alert message. The name of entry reference and "
378 "error message is shown."),
379 ref.name, strerror(status));
381 BAlert* alert = new BAlert(B_TRANSLATE("DiskProbe request"),
382 buffer, B_TRANSLATE("OK"), NULL, NULL,
383 B_WIDTH_AS_USUAL, B_STOP_ALERT);
384 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
385 alert->Go();
391 void
392 DiskProbe::ArgvReceived(int32 argc, char **argv)
394 BMessage *message = CurrentMessage();
396 BDirectory currentDirectory;
397 if (message)
398 currentDirectory.SetTo(message->FindString("cwd"));
400 BMessage refs;
402 for (int i = 1 ; i < argc ; i++) {
403 BPath path;
404 if (argv[i][0] == '/')
405 path.SetTo(argv[i]);
406 else
407 path.SetTo(&currentDirectory, argv[i]);
409 status_t status;
410 entry_ref ref;
411 BEntry entry;
413 if ((status = entry.SetTo(path.Path(), false)) != B_OK
414 || (status = entry.GetRef(&ref)) != B_OK) {
415 fprintf(stderr, B_TRANSLATE("Could not open file \"%s\": %s\n"),
416 path.Path(), strerror(status));
417 continue;
420 refs.AddRef("refs", &ref);
423 RefsReceived(&refs);
427 void
428 DiskProbe::MessageReceived(BMessage *message)
430 switch (message->what) {
431 case kMsgOpenOpenWindow:
432 if (fOpenWindow == NULL) {
433 fOpenWindow = new OpenWindow();
434 fOpenWindow->Show();
435 fWindowCount++;
436 } else
437 fOpenWindow->Activate(true);
438 break;
440 case kMsgOpenWindowClosed:
441 fOpenWindow = NULL;
442 // supposed to fall through
443 case kMsgWindowClosed:
444 if (--fWindowCount == 0 && !fFilePanel->IsShowing())
445 PostMessage(B_QUIT_REQUESTED);
446 break;
448 case kMsgSettingsChanged:
449 fSettings.UpdateFrom(message);
450 break;
452 case kMsgFindWindowClosed:
453 fFindWindow = NULL;
454 break;
455 case kMsgFindTarget:
457 BMessenger target;
458 if (message->FindMessenger("target", &target) != B_OK)
459 break;
461 if (fFindWindow != NULL && fFindWindow->Lock()) {
462 fFindWindow->SetTarget(target);
463 fFindWindow->Unlock();
465 break;
467 case kMsgOpenFindWindow:
469 BMessenger target;
470 if (message->FindMessenger("target", &target) != B_OK)
471 break;
473 if (fFindWindow == NULL) {
474 // open it!
475 fFindWindow = new FindWindow(fWindowFrame.OffsetByCopy(80, 80), *message,
476 target, &fSettings.Message());
477 fFindWindow->Show();
478 } else
479 fFindWindow->Activate();
480 break;
483 case kMsgOpenFilePanel:
484 fFilePanel->Show();
485 break;
486 case B_CANCEL:
487 if (fWindowCount == 0)
488 PostMessage(B_QUIT_REQUESTED);
489 break;
491 default:
492 BApplication::MessageReceived(message);
493 break;
498 bool
499 DiskProbe::QuitRequested()
501 return true;
505 // #pragma mark -
509 main(int argc, char **argv)
511 DiskProbe probe;
513 probe.Run();
514 return 0;