8 #include "PoorManWindow.h"
12 #include <arpa/inet.h>
17 #include <DateTimeFormat.h>
18 #include <Directory.h>
20 #include <FindDirectory.h>
21 #include <LayoutBuilder.h>
28 #include <ScrollBar.h>
29 #include <ScrollView.h>
30 #include <StringView.h>
31 #include <TypeConstants.h>
33 #include "PoorManApplication.h"
34 #include "PoorManPreferencesWindow.h"
35 #include "PoorManView.h"
36 #include "PoorManServer.h"
37 #include "PoorManLogger.h"
38 #include "constants.h"
41 #undef B_TRANSLATION_CONTEXT
42 #define B_TRANSLATION_CONTEXT "PoorMan"
43 #define DATE_FORMAT B_SHORT_DATE_FORMAT
44 #define TIME_FORMAT B_MEDIUM_TIME_FORMAT
47 PoorManWindow::PoorManWindow(BRect frame
)
49 BWindow(frame
, STR_APP_NAME
, B_TITLED_WINDOW
, B_AUTO_UPDATE_SIZE_LIMITS
),
57 fWebDirectory
.SetTo(STR_DEFAULT_WEB_DIRECTORY
);
58 fIndexFileName
.SetTo("index.html");
61 fLogConsoleFlag
= true;
65 fMaxConnections
= (int16
)32;
71 fSetwindowFrame
.Set(112.0f
, 60.0f
, 492.0f
, 340.0f
);
74 SetSizeLimits(318, 1600, 53, 1200);
75 // limit the size of the size of the window
77 // -----------------------------------------------------------------
81 fStatusView
= new BStringView("Status View", B_TRANSLATE("Status: Stopped"));
84 fDirView
= new BStringView("Dir View", B_TRANSLATE("Directory: (none)"));
87 fHitsView
= new BStringView("Hit View", B_TRANSLATE("Hits: 0"));
89 // -----------------------------------------------------------------
92 fLoggingView
= new BTextView(STR_TXT_VIEW
, B_WILL_DRAW
);
94 fLoggingView
->MakeEditable(false); // user cannot change the text
95 fLoggingView
->MakeSelectable(true);
96 fLoggingView
->SetViewColor(WHITE
);
97 fLoggingView
->SetStylable(true);
99 // create the scroll view
100 fScrollView
= new BScrollView("Scroll View", fLoggingView
,
101 B_WILL_DRAW
| B_FRAME_EVENTS
,
102 // Make sure articles on border do not occur when resizing
104 fLoggingView
->MakeFocus(true);
107 // -----------------------------------------------------------------
109 fFileMenuBar
= new BMenuBar("File Menu Bar");
112 fFileMenu
= BuildFileMenu();
114 fFileMenuBar
->AddItem(fFileMenu
);
116 fEditMenu
= BuildEditMenu();
118 fFileMenuBar
->AddItem(fEditMenu
);
120 fControlsMenu
= BuildControlsMenu();
122 fFileMenuBar
->AddItem(fControlsMenu
);
125 BWindow
* change_title
;
127 fSaveConsoleFilePanel
= new BFilePanel(B_SAVE_PANEL
, new BMessenger(this),
128 NULL
, B_FILE_NODE
, false,
129 new BMessage(MSG_FILE_PANEL_SAVE_CONSOLE
));
130 change_title
= fSaveConsoleFilePanel
->Window();
131 change_title
->SetTitle(STR_FILEPANEL_SAVE_CONSOLE
);
133 fSaveConsoleSelectionFilePanel
= new BFilePanel(B_SAVE_PANEL
,
134 new BMessenger(this), NULL
, B_FILE_NODE
, false,
135 new BMessage(MSG_FILE_PANEL_SAVE_CONSOLE_SELECTION
));
136 change_title
= fSaveConsoleSelectionFilePanel
->Window();
137 change_title
->SetTitle(STR_FILEPANEL_SAVE_CONSOLE_SELECTION
);
139 BLayoutBuilder::Group
<>(this, B_VERTICAL
, 0)
142 .AddGroup(B_VERTICAL
, B_USE_SMALL_SPACING
)
143 .SetInsets(B_USE_WINDOW_INSETS
)
144 .AddGroup(B_HORIZONTAL
)
149 .AddGroup(B_HORIZONTAL
)
155 pthread_rwlock_init(&fLogFileLock
, NULL
);
159 PoorManWindow::~PoorManWindow()
163 pthread_rwlock_destroy(&fLogFileLock
);
168 PoorManWindow::MessageReceived(BMessage
* message
)
170 switch (message
->what
) {
171 case MSG_MENU_FILE_SAVE_AS
:
172 fSaveConsoleFilePanel
->Show();
174 case MSG_FILE_PANEL_SAVE_CONSOLE
:
175 printf("FilePanel: Save console\n");
176 SaveConsole(message
, false);
178 case MSG_MENU_FILE_SAVE_SELECTION
:
179 fSaveConsoleSelectionFilePanel
->Show();
181 case MSG_FILE_PANEL_SAVE_CONSOLE_SELECTION
:
182 printf("FilePanel: Save console selection\n");
183 SaveConsole(message
, true);
185 case MSG_FILE_PANEL_SELECT_WEB_DIR
:
186 fPrefWindow
->MessageReceived(message
);
188 case MSG_MENU_EDIT_PREF
:
189 fPrefWindow
= new PoorManPreferencesWindow(fSetwindowFrame
,
193 case MSG_MENU_CTRL_RUN
:
199 case MSG_MENU_CTRL_CLEAR_HIT
:
203 case MSG_MENU_CTRL_CLEAR_CONSOLE
:
204 fLoggingView
->SelectAll();
205 fLoggingView
->Delete();
207 case MSG_MENU_CTRL_CLEAR_LOG
:
209 f
= fopen(fLogPath
.String(), "w");
213 if (!fLogConsoleFlag
&& !fLogFileFlag
)
224 if (message
->FindString("cstring", &msg
) != B_OK
)
226 if (message
->FindData("time_t", B_TIME_TYPE
, &pointer
, &size
) != B_OK
)
229 time
= *static_cast<const time_t*>(pointer
);
231 if (message
->FindData("in_addr_t", B_ANY_TYPE
, &pointer
, &size
) != B_OK
)
232 address
= INADDR_NONE
;
234 address
= *static_cast<const in_addr_t
*>(pointer
);
236 if (message
->FindData("rgb_color", B_RGB_COLOR_TYPE
, &pointer
, &size
) != B_OK
)
239 color
= *static_cast<const rgb_color
*>(pointer
);
243 if (BDateTimeFormat().Format(timeString
, time
, DATE_FORMAT
,
244 TIME_FORMAT
) == B_OK
) {
245 line
<< '[' << timeString
<< "]: ";
249 if (address
!= INADDR_NONE
) {
250 char addr
[INET_ADDRSTRLEN
];
251 struct in_addr sin_addr
;
252 sin_addr
.s_addr
= address
;
253 if (inet_ntop(AF_INET
, &sin_addr
, addr
, sizeof(addr
)) != NULL
) {
254 addr
[strlen(addr
)] = '\0';
255 line
<< '(' << addr
<< ") ";
271 if (fLogConsoleFlag
) {
272 fLoggingView
->Insert(fLoggingView
->TextLength(),
273 line
.String(), line
.Length(), &runs
);
274 fLoggingView
->ScrollToOffset(fLoggingView
->TextLength());
278 if (pthread_rwlock_rdlock(&fLogFileLock
) == 0) {
279 fLogFile
->Write(line
.String(), line
.Length());
280 pthread_rwlock_unlock(&fLogFileLock
);
290 BWindow::MessageReceived(message
);
297 PoorManWindow::FrameMoved(BPoint origin
)
299 fFrame
.left
= origin
.x
;
300 fFrame
.top
= origin
.y
;
305 PoorManWindow::FrameResized(float width
, float height
)
309 fLastHeight
= height
;
315 PoorManWindow::QuitRequested()
318 time_t now
= time(NULL
);
320 BDateTimeFormat().Format(timeString
, now
, DATE_FORMAT
, TIME_FORMAT
);
323 line
<< "[" << timeString
<< "]: " << B_TRANSLATE("Shutting down.")
326 if (fLogConsoleFlag
) {
327 fLoggingView
->Insert(fLoggingView
->TextLength(),
328 line
, line
.Length());
329 fLoggingView
->ScrollToOffset(fLoggingView
->TextLength());
333 if (pthread_rwlock_rdlock(&fLogFileLock
) == 0) {
334 fLogFile
->Write(line
, line
.Length());
335 pthread_rwlock_unlock(&fLogFileLock
);
341 UpdateStatusLabelAndMenuItem();
345 be_app_messenger
.SendMessage(B_QUIT_REQUESTED
);
351 PoorManWindow::Zoom(BPoint origin
, float width
, float height
)
354 // Change to the Minimal size
358 // Change to the Zoomed size
360 ResizeTo(fLastWidth
, fLastHeight
);
366 PoorManWindow::SetHits(uint32 num
)
373 // Private: Methods ------------------------------------------
377 PoorManWindow::BuildFileMenu() const
379 BMenu
* ptrFileMenu
= new BMenu(STR_MNU_FILE
);
381 ptrFileMenu
->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_AS
,
382 new BMessage(MSG_MENU_FILE_SAVE_AS
), CMD_FILE_SAVE_AS
));
384 ptrFileMenu
->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_SELECTION
,
385 new BMessage(MSG_MENU_FILE_SAVE_SELECTION
)));
387 ptrFileMenu
->AddSeparatorItem();
389 ptrFileMenu
->AddItem(new BMenuItem(STR_MNU_FILE_QUIT
,
390 new BMessage(B_QUIT_REQUESTED
), CMD_FILE_QUIT
));
397 PoorManWindow::BuildEditMenu() const
399 BMenu
* ptrEditMenu
= new BMenu(STR_MNU_EDIT
);
401 BMenuItem
* CopyMenuItem
= new BMenuItem(STR_MNU_EDIT_COPY
,
402 new BMessage(B_COPY
), CMD_EDIT_COPY
);
404 ptrEditMenu
->AddItem(CopyMenuItem
);
405 CopyMenuItem
->SetTarget(fLoggingView
, NULL
);
407 ptrEditMenu
->AddSeparatorItem();
409 BMenuItem
* SelectAllMenuItem
= new BMenuItem(STR_MNU_EDIT_SELECT_ALL
,
410 new BMessage(B_SELECT_ALL
), CMD_EDIT_SELECT_ALL
);
412 ptrEditMenu
->AddItem(SelectAllMenuItem
);
413 SelectAllMenuItem
->SetTarget(fLoggingView
, NULL
);
415 ptrEditMenu
->AddSeparatorItem();
417 BMenuItem
* PrefMenuItem
= new BMenuItem(STR_MNU_EDIT_PREF
,
418 new BMessage(MSG_MENU_EDIT_PREF
));
419 ptrEditMenu
->AddItem(PrefMenuItem
);
426 PoorManWindow::BuildControlsMenu() const
428 BMenu
* ptrControlMenu
= new BMenu(STR_MNU_CTRL
);
430 BMenuItem
* RunServerMenuItem
= new BMenuItem(STR_MNU_CTRL_RUN_SERVER
,
431 new BMessage(MSG_MENU_CTRL_RUN
));
432 RunServerMenuItem
->SetMarked(false);
433 ptrControlMenu
->AddItem(RunServerMenuItem
);
435 BMenuItem
* ClearHitCounterMenuItem
= new BMenuItem(STR_MNU_CTRL_CLEAR_HIT_COUNTER
,
436 new BMessage(MSG_MENU_CTRL_CLEAR_HIT
));
437 ptrControlMenu
->AddItem(ClearHitCounterMenuItem
);
439 ptrControlMenu
->AddSeparatorItem();
441 BMenuItem
* ClearConsoleLogMenuItem
= new BMenuItem(STR_MNU_CTRL_CLEAR_CONSOLE
,
442 new BMessage(MSG_MENU_CTRL_CLEAR_CONSOLE
));
443 ptrControlMenu
->AddItem(ClearConsoleLogMenuItem
);
445 BMenuItem
* ClearLogFileMenuItem
= new BMenuItem(STR_MNU_CTRL_CLEAR_LOG_FILE
,
446 new BMessage(MSG_MENU_CTRL_CLEAR_LOG
));
447 ptrControlMenu
->AddItem(ClearLogFileMenuItem
);
449 return ptrControlMenu
;
454 PoorManWindow::SetDirLabel(const char* name
)
456 BString
dirPath(B_TRANSLATE("Directory: "));
457 dirPath
.Append(name
);
460 fDirView
->SetText(dirPath
.String());
467 PoorManWindow::UpdateStatusLabelAndMenuItem()
471 fStatusView
->SetText(B_TRANSLATE("Status: Running"));
473 fStatusView
->SetText(B_TRANSLATE("Status: Stopped"));
474 fControlsMenu
->FindItem(STR_MNU_CTRL_RUN_SERVER
)->SetMarked(fStatus
);
481 PoorManWindow::UpdateHitsLabel()
484 sprintf(fHitsLabel
, B_TRANSLATE("Hits: %lu"), GetHits());
485 fHitsView
->SetText(fHitsLabel
);
493 PoorManWindow::SaveConsole(BMessage
* message
, bool selection
)
502 err
= message
->FindRef("directory", &ref
);
506 err
= message
->FindString("name", &name
);
510 err
= entry
.SetTo(&ref
);
514 entry
.GetPath(&path
);
517 if (!(f
= fopen(path
.Path(), "w")))
521 // write the data to the file
522 err
= fwrite(fLoggingView
->Text(), 1, fLoggingView
->TextLength(), f
);
524 // find the selected text and write it to a file
525 int32 start
= 0, end
= 0;
526 fLoggingView
->GetSelection(&start
, &end
);
529 char * buffData
= buffer
.LockBuffer(end
- start
+ 1);
530 // copy the selected text from the TextView to the buffer
531 fLoggingView
->GetText(start
, end
- start
, buffData
);
532 buffer
.UnlockBuffer(end
- start
+ 1);
534 err
= fwrite(buffer
.String(), 1, end
- start
+ 1, f
);
544 PoorManWindow::DefaultSettings()
546 BAlert
* serverAlert
= new BAlert(B_TRANSLATE("Error Server"),
547 STR_ERR_CANT_START
, B_TRANSLATE("OK"));
548 serverAlert
->SetFlags(serverAlert
->Flags() | B_CLOSE_ON_ESCAPE
);
549 BAlert
* dirAlert
= new BAlert(B_TRANSLATE("Error Dir"),
550 STR_ERR_WEB_DIR
, B_TRANSLATE("Cancel"), B_TRANSLATE("Select"),
551 B_TRANSLATE("Create public_html"), B_WIDTH_AS_USUAL
, B_OFFSET_SPACING
);
552 dirAlert
->SetShortcut(0, B_ESCAPE
);
553 int32 buttonIndex
= dirAlert
->Go();
555 switch (buttonIndex
) {
559 be_app_messenger
.SendMessage(B_QUIT_REQUESTED
);
563 fPrefWindow
= new PoorManPreferencesWindow(
566 fPrefWindow
->ShowWebDirFilePanel();
570 if (create_directory(STR_DEFAULT_WEB_DIRECTORY
, 0755) != B_OK
) {
574 be_app_messenger
.SendMessage(B_QUIT_REQUESTED
);
577 BAlert
* dirCreatedAlert
=
578 new BAlert(B_TRANSLATE("Dir Created"), STR_DIR_CREATED
,
580 dirCreatedAlert
->SetFlags(dirCreatedAlert
->Flags() | B_CLOSE_ON_ESCAPE
);
581 dirCreatedAlert
->Go();
582 SetWebDir(STR_DEFAULT_WEB_DIRECTORY
);
583 be_app
->PostMessage(kStartServer
);
590 PoorManWindow::ReadSettings()
596 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &p
) != B_OK
)
598 p
.Append(STR_SETTINGS_FILE_NAME
);
600 f
.SetTo(p
.Path(), B_READ_ONLY
);
601 if (f
.InitCheck() != B_OK
)
604 if (m
.Unflatten(&f
) != B_OK
)
607 if (MSG_PREF_FILE
!= m
.what
)
611 if (m
.FindString("fWebDirectory", &fWebDirectory
) != B_OK
)
612 fWebDirectory
.SetTo(STR_DEFAULT_WEB_DIRECTORY
);
613 if (m
.FindString("fIndexFileName", &fIndexFileName
) != B_OK
)
614 fIndexFileName
.SetTo("index.html");
615 if (m
.FindBool("fDirListFlag", &fDirListFlag
) != B_OK
)
616 fDirListFlag
= false;
619 if (m
.FindBool("fLogConsoleFlag", &fLogConsoleFlag
) != B_OK
)
620 fLogConsoleFlag
= true;
621 if (m
.FindBool("fLogFileFlag", &fLogFileFlag
) != B_OK
)
622 fLogFileFlag
= false;
623 if (m
.FindString("fLogPath", &fLogPath
) != B_OK
)
627 if (m
.FindInt16("fMaxConnections", &fMaxConnections
) != B_OK
)
628 fMaxConnections
= (int16
)32;
630 //windows' position and size
631 if (m
.FindRect("frame", &fFrame
) != B_OK
)
632 fFrame
.Set(82.0f
, 30.0f
, 400.0f
, 350.0f
);
633 if (m
.FindRect("fSetwindowFrame", &fSetwindowFrame
) != B_OK
)
634 fSetwindowFrame
.Set(112.0f
, 60.0f
, 492.0f
, 340.0f
);
635 if (m
.FindBool("fIsZoomed", &fIsZoomed
) != B_OK
)
637 if (m
.FindFloat("fLastWidth", &fLastWidth
) != B_OK
)
639 if (m
.FindFloat("fLastHeight", &fLastHeight
) != B_OK
)
640 fLastHeight
= 320.0f
;
642 fIsZoomed
?ResizeTo(fLastWidth
, fLastHeight
):ResizeTo(318, 53);
643 MoveTo(fFrame
.left
, fFrame
.top
);
645 fLogFile
= new BFile(fLogPath
.String(), B_CREATE_FILE
| B_WRITE_ONLY
647 if (fLogFile
->InitCheck() != B_OK
) {
648 fLogFileFlag
= false;
649 //log it to console, "log to file unavailable."
653 SetDirLabel(fWebDirectory
.String());
660 PoorManWindow::SaveSettings()
664 BMessage
m(MSG_PREF_FILE
);
667 m
.AddString("fWebDirectory", fWebDirectory
);
668 m
.AddString("fIndexFileName", fIndexFileName
);
669 m
.AddBool("fDirListFlag", fDirListFlag
);
672 m
.AddBool("fLogConsoleFlag", fLogConsoleFlag
);
673 m
.AddBool("fLogFileFlag", fLogFileFlag
);
674 m
.AddString("fLogPath", fLogPath
);
677 m
.AddInt16("fMaxConnections", fMaxConnections
);
679 //windows' position and size
680 m
.AddRect("frame", fFrame
);
681 m
.AddRect("fSetwindowFrame", fSetwindowFrame
);
682 m
.AddBool("fIsZoomed", fIsZoomed
);
683 m
.AddFloat("fLastWidth", fLastWidth
);
684 m
.AddFloat("fLastHeight", fLastHeight
);
686 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &p
) != B_OK
)
688 p
.Append(STR_SETTINGS_FILE_NAME
);
690 f
.SetTo(p
.Path(), B_WRITE_ONLY
| B_ERASE_FILE
| B_CREATE_FILE
);
691 if (f
.InitCheck() != B_OK
)
694 if (m
.Flatten(&f
) != B_OK
)
702 PoorManWindow::StartServer()
705 fServer
= new PoorManServer(fWebDirectory
.String(), fMaxConnections
,
706 fDirListFlag
, fIndexFileName
.String());
708 poorman_log(B_TRANSLATE("Starting up... "));
709 if (fServer
->Run() != B_OK
) {
714 UpdateStatusLabelAndMenuItem();
715 poorman_log(B_TRANSLATE("done.\n"), false, INADDR_NONE
, GREEN
);
722 PoorManWindow::StopServer()
727 poorman_log(B_TRANSLATE("Shutting down.\n"));
730 UpdateStatusLabelAndMenuItem();
736 PoorManWindow::SetLogPath(const char* str
)
738 if (!strcmp(fLogPath
, str
))
741 BFile
* temp
= new BFile(str
, B_CREATE_FILE
| B_WRITE_ONLY
| B_OPEN_AT_END
);
743 if (temp
->InitCheck() != B_OK
) {
748 if (pthread_rwlock_wrlock(&fLogFileLock
) == 0) {
751 pthread_rwlock_unlock(&fLogFileLock
);