2 * Copyright 2004-2015, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
12 #include <AboutWindow.h>
14 #include <Application.h>
17 #include <Directory.h>
19 #include <FilePanel.h>
20 #include <FindDirectory.h>
21 #include <LayoutUtils.h>
27 #include "DataEditor.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
{
53 enum disk_probe_flags
{
54 kCaseSensitive
= 0x01, // this flag alone is R5 DiskProbe settings compatible
64 const BMessage
&Message() const { return fMessage
; }
65 void UpdateFrom(BMessage
*message
);
68 status_t
Open(BFile
*file
, int32 mode
);
75 class DiskProbe
: public BApplication
{
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();
89 status_t
Probe(BEntry
&entry
, const char *attribute
= NULL
);
92 BFilePanel
*fFilePanel
;
94 FindWindow
*fFindWindow
;
97 BMessenger fFindTarget
;
106 fMessage(kMsgDiskProbeSettings
),
109 float fontSize
= be_plain_font
->Size();
110 int32 windowWidth
= DataView::WidthForFontSize(fontSize
) + 20;
111 // TODO: make scrollbar width variable
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
);
123 if (Open(&file
, B_READ_ONLY
) != B_OK
)
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
);
142 // check if the window frame is on screen at all
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
172 if (Open(&file
, B_CREATE_FILE
| B_WRITE_ONLY
) != B_OK
)
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
);
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
));
203 Settings::Open(BFile
*file
, int32 mode
)
206 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) != B_OK
)
209 path
.Append("DiskProbe_data");
211 return file
->SetTo(path
.Path(), mode
);
216 Settings::UpdateFrom(BMessage
*message
)
219 if (message
->FindRect("window_frame", &frame
) == B_OK
)
220 fMessage
.ReplaceRect("window_frame", frame
);
223 if (message
->FindInt32("base_type", &baseType
) == B_OK
)
224 fMessage
.ReplaceInt32("base_type", baseType
);
227 if (message
->FindFloat("font_size", &fontSize
) == B_OK
)
228 fMessage
.ReplaceFloat("font_size", fontSize
);
231 if (message
->FindBool("case_sensitive", &caseSensitive
) == B_OK
)
232 fMessage
.ReplaceBool("case_sensitive", caseSensitive
);
235 if (message
->FindInt8("find_mode", &findMode
) == B_OK
)
236 fMessage
.ReplaceInt8("find_mode", findMode
);
245 DiskProbe::DiskProbe()
246 : BApplication(kSignature
),
251 fFilePanel
= new BFilePanel();
252 fWindowFrame
= fSettings
.Message().FindRect("window_frame");
256 DiskProbe::~DiskProbe()
263 DiskProbe::ReadyToRun()
265 // are there already windows open?
266 if (CountWindows() != 1)
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
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.
283 DiskProbe::Probe(BEntry
&entry
, const char *attribute
)
286 status_t status
= entry
.GetRef(&ref
);
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
));
298 if (window
->Contains(ref
, attribute
)) {
299 window
->Activate(true);
302 if (lastWindow
== NULL
)
306 // Does the file really exist?
308 return B_ENTRY_NOT_FOUND
;
314 if (lastWindow
!= NULL
)
315 rect
= lastWindow
->Frame();
319 rect
.OffsetBy(kCascadeOffset
, kCascadeOffset
);
322 if (attribute
!= NULL
)
323 window
= new AttributeWindow(rect
, &ref
, attribute
, &fSettings
.Message());
325 window
= new FileWindow(rect
, &ref
, &fSettings
.Message());
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
;
335 BRect screenBorder
= screen
.Frame();
337 float left
= rect
.left
;
338 if (left
+ rect
.Width() > screenBorder
.right
)
341 float top
= rect
.top
;
342 if (top
+ rect
.Height() > screenBorder
.bottom
)
345 rect
.OffsetTo(BPoint(left
, top
));
346 window
->MoveTo(BPoint(left
, top
));
355 DiskProbe::RefsReceived(BMessage
*message
)
357 bool traverseLinks
= (modifiers() & B_SHIFT_KEY
) == 0;
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;
367 status_t status
= entry
.SetTo(&ref
, traverseLinks
);
370 status
= Probe(entry
, attribute
);
372 if (status
!= B_OK
) {
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
);
392 DiskProbe::ArgvReceived(int32 argc
, char **argv
)
394 BMessage
*message
= CurrentMessage();
396 BDirectory currentDirectory
;
398 currentDirectory
.SetTo(message
->FindString("cwd"));
402 for (int i
= 1 ; i
< argc
; i
++) {
404 if (argv
[i
][0] == '/')
407 path
.SetTo(¤tDirectory
, argv
[i
]);
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
));
420 refs
.AddRef("refs", &ref
);
428 DiskProbe::MessageReceived(BMessage
*message
)
430 switch (message
->what
) {
431 case kMsgOpenOpenWindow
:
432 if (fOpenWindow
== NULL
) {
433 fOpenWindow
= new OpenWindow();
437 fOpenWindow
->Activate(true);
440 case kMsgOpenWindowClosed
:
442 // supposed to fall through
443 case kMsgWindowClosed
:
444 if (--fWindowCount
== 0 && !fFilePanel
->IsShowing())
445 PostMessage(B_QUIT_REQUESTED
);
448 case kMsgSettingsChanged
:
449 fSettings
.UpdateFrom(message
);
452 case kMsgFindWindowClosed
:
458 if (message
->FindMessenger("target", &target
) != B_OK
)
461 if (fFindWindow
!= NULL
&& fFindWindow
->Lock()) {
462 fFindWindow
->SetTarget(target
);
463 fFindWindow
->Unlock();
467 case kMsgOpenFindWindow
:
470 if (message
->FindMessenger("target", &target
) != B_OK
)
473 if (fFindWindow
== NULL
) {
475 fFindWindow
= new FindWindow(fWindowFrame
.OffsetByCopy(80, 80), *message
,
476 target
, &fSettings
.Message());
479 fFindWindow
->Activate();
483 case kMsgOpenFilePanel
:
487 if (fWindowCount
== 0)
488 PostMessage(B_QUIT_REQUESTED
);
492 BApplication::MessageReceived(message
);
499 DiskProbe::QuitRequested()
509 main(int argc
, char **argv
)