Merge branch 'master' into x86_64
This commit is contained in:
+1
-1
@@ -199,7 +199,7 @@ rule ExtractArchive directory : entries : archiveFile : grist
|
|||||||
# <directory> and <archiveFile> combo.
|
# <directory> and <archiveFile> combo.
|
||||||
#
|
#
|
||||||
# <directory> - The directory into which to extract the archive file. The
|
# <directory> - The directory into which to extract the archive file. The
|
||||||
# directory is created is by this rule and it is the target
|
# directory is created by this rule and it is the target
|
||||||
# that the extract action is associated with.
|
# that the extract action is associated with.
|
||||||
# <entries> - The entries of the archive file one is interested in. The
|
# <entries> - The entries of the archive file one is interested in. The
|
||||||
# rule always extracts the complete archive file, from the
|
# rule always extracts the complete archive file, from the
|
||||||
|
|||||||
@@ -419,3 +419,36 @@ if $(HAIKU_BUILD_FEATURE_TAGLIB) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# WebKit
|
||||||
|
local webkitBaseURL = http://haiku-files.org/files/optional-packages ;
|
||||||
|
if $(TARGET_ARCH) = x86 {
|
||||||
|
if $(HAIKU_GCC_VERSION[1]) < 4 {
|
||||||
|
Echo "WebKit support not available on gcc $(HAIKU_GCC_VERSION[1])" ;
|
||||||
|
} else {
|
||||||
|
HAIKU_WEBKIT_FILE = webkit-0.1.1-x86-gcc4-2012-07-03.zip ;
|
||||||
|
|
||||||
|
local zipFile = [ DownloadFile $(HAIKU_WEBKIT_FILE)
|
||||||
|
: $(webkitBaseURL)/$(HAIKU_WEBKIT_FILE) ] ;
|
||||||
|
|
||||||
|
HAIKU_WEBKIT_DIR = [ FDirName $(HAIKU_OPTIONAL_BUILD_PACKAGES_DIR)
|
||||||
|
$(HAIKU_WEBKIT_FILE:B) ] ;
|
||||||
|
|
||||||
|
HAIKU_WEBKIT_HEADERS_DEPENDENCY = [ ExtractArchive $(HAIKU_WEBKIT_DIR)
|
||||||
|
: include/ : $(zipFile) : extracted-webkit ] ;
|
||||||
|
|
||||||
|
HAIKU_WEBKIT_LIBS = [ ExtractArchive $(HAIKU_WEBKIT_DIR)
|
||||||
|
:
|
||||||
|
lib/libwtf.so
|
||||||
|
lib/libjavascriptcore.so
|
||||||
|
lib/libwebcore.so
|
||||||
|
lib/libwebkit.so
|
||||||
|
: $(zipFile)
|
||||||
|
: extracted-webkit
|
||||||
|
] ;
|
||||||
|
|
||||||
|
HAIKU_WEBKIT_HEADERS = [ FDirName $(HAIKU_WEBKIT_DIR) include ] ;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Echo "WebKit support not available on $(TARGET_ARCH)" ;
|
||||||
|
}
|
||||||
|
|||||||
@@ -359,8 +359,8 @@ if [ IsOptionalHaikuImagePackageAdded Bzip ] {
|
|||||||
|
|
||||||
# CARootCertificates
|
# CARootCertificates
|
||||||
if [ IsOptionalHaikuImagePackageAdded CARootCertificates ] {
|
if [ IsOptionalHaikuImagePackageAdded CARootCertificates ] {
|
||||||
InstallOptionalHaikuImagePackage cert-2012-05-02.zip
|
InstallOptionalHaikuImagePackage cert-2012-07-04.zip
|
||||||
: $(baseURL)/cert-2012-05-02.zip
|
: $(baseURL)/cert-2012-07-04.zip
|
||||||
: common data ssl ;
|
: common data ssl ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,5 +59,6 @@ HaikuSubInclude terminal ;
|
|||||||
HaikuSubInclude text_search ;
|
HaikuSubInclude text_search ;
|
||||||
HaikuSubInclude tracker ;
|
HaikuSubInclude tracker ;
|
||||||
HaikuSubInclude tv ;
|
HaikuSubInclude tv ;
|
||||||
|
HaikuSubInclude webpositive ;
|
||||||
HaikuSubInclude webwatch ;
|
HaikuSubInclude webwatch ;
|
||||||
HaikuSubInclude workspaces ;
|
HaikuSubInclude workspaces ;
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AuthenticationPanel.h"
|
||||||
|
|
||||||
|
#include <Button.h>
|
||||||
|
#include <CheckBox.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <GridLayoutBuilder.h>
|
||||||
|
#include <GroupLayoutBuilder.h>
|
||||||
|
#include <Message.h>
|
||||||
|
#include <Screen.h>
|
||||||
|
#include <SeparatorView.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
#include <StringView.h>
|
||||||
|
#include <TextControl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static const uint32 kMsgPanelOK = 'pnok';
|
||||||
|
static const uint32 kMsgJitter = 'jitr';
|
||||||
|
static const uint32 kHidePassword = 'hdpw';
|
||||||
|
|
||||||
|
AuthenticationPanel::AuthenticationPanel(BRect parentFrame)
|
||||||
|
: BWindow(BRect(-1000, -1000, -900, -900), "Authentication Required",
|
||||||
|
B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL,
|
||||||
|
B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE | B_NOT_ZOOMABLE
|
||||||
|
| B_CLOSE_ON_ESCAPE | B_AUTO_UPDATE_SIZE_LIMITS)
|
||||||
|
, m_parentWindowFrame(parentFrame)
|
||||||
|
, m_usernameTextControl(new BTextControl("user", "Username:", "", NULL))
|
||||||
|
, m_passwordTextControl(new BTextControl("pass", "Password:", "", NULL))
|
||||||
|
, m_hidePasswordCheckBox(new BCheckBox("hide", "Hide password text", new BMessage(kHidePassword)))
|
||||||
|
, m_rememberCredentialsCheckBox(new BCheckBox("remember", "Remember username and password for this site", NULL))
|
||||||
|
, m_okButton(new BButton("ok", "OK", new BMessage(kMsgPanelOK)))
|
||||||
|
, m_cancelButton(new BButton("cancel", "Cancel", new BMessage(B_QUIT_REQUESTED)))
|
||||||
|
, m_cancelled(false)
|
||||||
|
, m_exitSemaphore(create_sem(0, "Authentication Panel"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthenticationPanel::~AuthenticationPanel()
|
||||||
|
{
|
||||||
|
delete_sem(m_exitSemaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AuthenticationPanel::QuitRequested()
|
||||||
|
{
|
||||||
|
m_cancelled = true;
|
||||||
|
release_sem(m_exitSemaphore);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AuthenticationPanel::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case kMsgPanelOK:
|
||||||
|
release_sem(m_exitSemaphore);
|
||||||
|
break;
|
||||||
|
case kHidePassword: {
|
||||||
|
// TODO: Toggling this is broken in BTextView. Workaround is to
|
||||||
|
// set the text and selection again.
|
||||||
|
BString text = m_passwordTextControl->Text();
|
||||||
|
int32 selectionStart;
|
||||||
|
int32 selectionEnd;
|
||||||
|
m_passwordTextControl->TextView()->GetSelection(&selectionStart, &selectionEnd);
|
||||||
|
m_passwordTextControl->TextView()->HideTyping(
|
||||||
|
m_hidePasswordCheckBox->Value() == B_CONTROL_ON);
|
||||||
|
m_passwordTextControl->SetText(text.String());
|
||||||
|
m_passwordTextControl->TextView()->Select(selectionStart, selectionEnd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kMsgJitter: {
|
||||||
|
UpdateIfNeeded();
|
||||||
|
BPoint leftTop = Frame().LeftTop();
|
||||||
|
const float jitterOffsets[] = { -10, 0, 10, 0 };
|
||||||
|
const int32 jitterOffsetCount = sizeof(jitterOffsets) / sizeof(float);
|
||||||
|
for (int32 i = 0; i < 20; i++) {
|
||||||
|
float offset = jitterOffsets[i % jitterOffsetCount];
|
||||||
|
MoveTo(leftTop.x + offset, leftTop.y);
|
||||||
|
snooze(15000);
|
||||||
|
}
|
||||||
|
MoveTo(leftTop);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BWindow::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AuthenticationPanel::getAuthentication(const BString& text,
|
||||||
|
const BString& previousUser, const BString& previousPass,
|
||||||
|
bool previousRememberCredentials, bool badPassword,
|
||||||
|
BString& user, BString& pass, bool* rememberCredentials)
|
||||||
|
{
|
||||||
|
// Configure panel and layout controls.
|
||||||
|
rgb_color infoColor = ui_color(B_PANEL_TEXT_COLOR);
|
||||||
|
BRect textBounds(0, 0, 250, 200);
|
||||||
|
BTextView* textView = new BTextView(textBounds, "text", textBounds,
|
||||||
|
be_plain_font, &infoColor, B_FOLLOW_NONE, B_WILL_DRAW | B_SUPPORTS_LAYOUT);
|
||||||
|
textView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
textView->SetText(text.String());
|
||||||
|
textView->MakeEditable(false);
|
||||||
|
textView->MakeSelectable(false);
|
||||||
|
|
||||||
|
m_usernameTextControl->SetText(previousUser.String());
|
||||||
|
m_passwordTextControl->TextView()->HideTyping(true);
|
||||||
|
// Ignore the previous password, if it didn't work.
|
||||||
|
if (!badPassword)
|
||||||
|
m_passwordTextControl->SetText(previousPass.String());
|
||||||
|
m_hidePasswordCheckBox->SetValue(B_CONTROL_ON);
|
||||||
|
m_rememberCredentialsCheckBox->SetValue(previousRememberCredentials);
|
||||||
|
|
||||||
|
// create layout
|
||||||
|
SetLayout(new BGroupLayout(B_VERTICAL, 0.0));
|
||||||
|
float spacing = be_control_look->DefaultItemSpacing();
|
||||||
|
AddChild(BGroupLayoutBuilder(B_VERTICAL, 0.0)
|
||||||
|
.Add(BGridLayoutBuilder(0, spacing)
|
||||||
|
.Add(textView, 0, 0, 2)
|
||||||
|
.Add(m_usernameTextControl->CreateLabelLayoutItem(), 0, 1)
|
||||||
|
.Add(m_usernameTextControl->CreateTextViewLayoutItem(), 1, 1)
|
||||||
|
.Add(m_passwordTextControl->CreateLabelLayoutItem(), 0, 2)
|
||||||
|
.Add(m_passwordTextControl->CreateTextViewLayoutItem(), 1, 2)
|
||||||
|
.Add(BSpaceLayoutItem::CreateGlue(), 0, 3)
|
||||||
|
.Add(m_hidePasswordCheckBox, 1, 3)
|
||||||
|
.Add(m_rememberCredentialsCheckBox, 0, 4, 2)
|
||||||
|
.SetInsets(spacing, spacing, spacing, spacing)
|
||||||
|
)
|
||||||
|
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
|
||||||
|
.Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing)
|
||||||
|
.AddGlue()
|
||||||
|
.Add(m_cancelButton)
|
||||||
|
.Add(m_okButton)
|
||||||
|
.SetInsets(spacing, spacing, spacing, spacing)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
float textHeight = textView->LineHeight(0) * textView->CountLines();
|
||||||
|
textView->SetExplicitMinSize(BSize(B_SIZE_UNSET, textHeight));
|
||||||
|
|
||||||
|
SetDefaultButton(m_okButton);
|
||||||
|
if (badPassword && previousUser.Length())
|
||||||
|
m_passwordTextControl->MakeFocus(true);
|
||||||
|
else
|
||||||
|
m_usernameTextControl->MakeFocus(true);
|
||||||
|
|
||||||
|
if (m_parentWindowFrame.IsValid())
|
||||||
|
CenterIn(m_parentWindowFrame);
|
||||||
|
else
|
||||||
|
CenterOnScreen();
|
||||||
|
|
||||||
|
// Start AuthenticationPanel window thread
|
||||||
|
Show();
|
||||||
|
|
||||||
|
// Let the window jitter, if the previous password was invalid
|
||||||
|
if (badPassword)
|
||||||
|
PostMessage(kMsgJitter);
|
||||||
|
|
||||||
|
// Block calling thread
|
||||||
|
// Get the originating window, if it exists, to let it redraw itself.
|
||||||
|
BWindow* window = dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL)));
|
||||||
|
if (window) {
|
||||||
|
status_t err;
|
||||||
|
for (;;) {
|
||||||
|
do {
|
||||||
|
err = acquire_sem_etc(m_exitSemaphore, 1, B_RELATIVE_TIMEOUT, 10000);
|
||||||
|
// We've (probably) had our time slice taken away from us
|
||||||
|
} while (err == B_INTERRUPTED);
|
||||||
|
|
||||||
|
if (err != B_TIMED_OUT) {
|
||||||
|
// Semaphore was finally released or nuked.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
window->UpdateIfNeeded();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No window to update, so just hang out until we're done.
|
||||||
|
while (acquire_sem(m_exitSemaphore) == B_INTERRUPTED) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticationPanel wants to quit.
|
||||||
|
Lock();
|
||||||
|
|
||||||
|
user = m_usernameTextControl->Text();
|
||||||
|
pass = m_passwordTextControl->Text();
|
||||||
|
if (rememberCredentials)
|
||||||
|
*rememberCredentials = m_rememberCredentialsCheckBox->Value() == B_CONTROL_ON;
|
||||||
|
|
||||||
|
bool canceled = m_cancelled;
|
||||||
|
Quit();
|
||||||
|
// AuthenticationPanel object is TOAST here.
|
||||||
|
return !canceled;
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AuthenticationPanel_h
|
||||||
|
#define AuthenticationPanel_h
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
class BCheckBox;
|
||||||
|
class BTextControl;
|
||||||
|
|
||||||
|
class AuthenticationPanel : public BWindow {
|
||||||
|
public:
|
||||||
|
AuthenticationPanel(BRect parentFrame = BRect());
|
||||||
|
virtual ~AuthenticationPanel();
|
||||||
|
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage *message);
|
||||||
|
|
||||||
|
bool getAuthentication(const BString& text, const BString& previousUser,
|
||||||
|
const BString& previousPass, bool previousRememberCredentials,
|
||||||
|
bool badPassword, BString& user, BString& pass,
|
||||||
|
bool* rememberCredentials);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BRect m_parentWindowFrame;
|
||||||
|
BTextControl* m_usernameTextControl;
|
||||||
|
BTextControl* m_passwordTextControl;
|
||||||
|
BCheckBox* m_hidePasswordCheckBox;
|
||||||
|
BCheckBox* m_rememberCredentialsCheckBox;
|
||||||
|
BButton* m_okButton;
|
||||||
|
BButton* m_cancelButton;
|
||||||
|
|
||||||
|
bool m_cancelled;
|
||||||
|
|
||||||
|
sem_id m_exitSemaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // AuthenticationPanel_h
|
||||||
@@ -0,0 +1,449 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Ryan Leavengood <[email protected]>
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BrowserApp.h"
|
||||||
|
|
||||||
|
#include "BrowserWindow.h"
|
||||||
|
#include "BrowsingHistory.h"
|
||||||
|
#include "DownloadWindow.h"
|
||||||
|
#include "SettingsMessage.h"
|
||||||
|
#include "SettingsWindow.h"
|
||||||
|
#include "svn_revision.h"
|
||||||
|
#include "NetworkCookieJar.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
#include "WebSettings.h"
|
||||||
|
#include "WebView.h"
|
||||||
|
#include <Alert.h>
|
||||||
|
#include <Autolock.h>
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Locale.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <Screen.h>
|
||||||
|
#include <debugger.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
const char* kApplicationSignature = "application/x-vnd.Haiku-WebPositive";
|
||||||
|
const char* kApplicationName = "WebPositive";
|
||||||
|
static const uint32 PRELOAD_BROWSING_HISTORY = 'plbh';
|
||||||
|
|
||||||
|
#define ENABLE_NATIVE_COOKIES 0
|
||||||
|
|
||||||
|
|
||||||
|
BrowserApp::BrowserApp()
|
||||||
|
:
|
||||||
|
BApplication(kApplicationSignature),
|
||||||
|
fWindowCount(0),
|
||||||
|
fLastWindowFrame(50, 50, 950, 750),
|
||||||
|
fLaunchRefsMessage(0),
|
||||||
|
fInitialized(false),
|
||||||
|
fSettings(NULL),
|
||||||
|
fCookies(NULL),
|
||||||
|
fCookieJar(NULL),
|
||||||
|
fDownloadWindow(NULL),
|
||||||
|
fSettingsWindow(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowserApp::~BrowserApp()
|
||||||
|
{
|
||||||
|
delete fLaunchRefsMessage;
|
||||||
|
delete fSettings;
|
||||||
|
delete fCookies;
|
||||||
|
delete fCookieJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::AboutRequested()
|
||||||
|
{
|
||||||
|
BString aboutText("WebPositive\n\nby Ryan Leavengood, Andrea Anzani, "
|
||||||
|
"Maxime Simon, Michael Lotz, Rene Gollent and Stephan Aßmus");
|
||||||
|
aboutText << "\n\nSVN revision: " << kSVNRevision;
|
||||||
|
|
||||||
|
BAlert* alert = new BAlert("About WebPositive", aboutText.String(),
|
||||||
|
"Sweet!");
|
||||||
|
alert->Go(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::ArgvReceived(int32 argc, char** argv)
|
||||||
|
{
|
||||||
|
BMessage message(B_REFS_RECEIVED);
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
if (strcmp("-f", argv[i]) == 0
|
||||||
|
|| strcmp("--fullscreen", argv[i]) == 0) {
|
||||||
|
message.AddBool("fullscreen", true);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char* url = argv[i];
|
||||||
|
BEntry entry(argv[i], true);
|
||||||
|
BPath path;
|
||||||
|
if (entry.Exists() && entry.GetPath(&path) == B_OK)
|
||||||
|
url = path.Path();
|
||||||
|
message.AddString("url", url);
|
||||||
|
}
|
||||||
|
// Upon program launch, it will buffer a copy of the message, since
|
||||||
|
// ArgReceived() is called before ReadyToRun().
|
||||||
|
RefsReceived(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::ReadyToRun()
|
||||||
|
{
|
||||||
|
// Since we will essentially run the GUI...
|
||||||
|
set_thread_priority(Thread(), B_DISPLAY_PRIORITY);
|
||||||
|
|
||||||
|
BWebPage::InitializeOnce();
|
||||||
|
BWebPage::SetCacheModel(B_WEBKIT_CACHE_MODEL_WEB_BROWSER);
|
||||||
|
|
||||||
|
BPath path;
|
||||||
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) == B_OK
|
||||||
|
&& path.Append(kApplicationName) == B_OK
|
||||||
|
&& create_directory(path.Path(), 0777) == B_OK) {
|
||||||
|
|
||||||
|
BWebSettings::SetPersistentStoragePath(path.Path());
|
||||||
|
}
|
||||||
|
|
||||||
|
BString mainSettingsPath(kApplicationName);
|
||||||
|
mainSettingsPath << "/Application";
|
||||||
|
fSettings = new SettingsMessage(B_USER_SETTINGS_DIRECTORY,
|
||||||
|
mainSettingsPath.String());
|
||||||
|
#if ENABLE_NATIVE_COOKIES
|
||||||
|
mainSettingsPath = kApplicationName;
|
||||||
|
mainSettingsPath << "/Cookies";
|
||||||
|
fCookies = new SettingsMessage(B_USER_SETTINGS_DIRECTORY,
|
||||||
|
mainSettingsPath.String());
|
||||||
|
BMessage cookieArchive;
|
||||||
|
cookieArchive = fCookies->GetValue("cookies", cookieArchive);
|
||||||
|
fCookieJar = new BNetworkCookieJar(cookieArchive);
|
||||||
|
BWebPage::SetCookieJar(fCookieJar);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fLastWindowFrame = fSettings->GetValue("window frame", fLastWindowFrame);
|
||||||
|
BRect defaultDownloadWindowFrame(-10, -10, 365, 265);
|
||||||
|
BRect downloadWindowFrame = fSettings->GetValue("downloads window frame",
|
||||||
|
defaultDownloadWindowFrame);
|
||||||
|
BRect settingsWindowFrame = fSettings->GetValue("settings window frame",
|
||||||
|
BRect());
|
||||||
|
bool showDownloads = fSettings->GetValue("show downloads", false);
|
||||||
|
|
||||||
|
fDownloadWindow = new DownloadWindow(downloadWindowFrame, showDownloads,
|
||||||
|
fSettings);
|
||||||
|
if (downloadWindowFrame == defaultDownloadWindowFrame) {
|
||||||
|
// Initially put download window in lower right of screen.
|
||||||
|
BRect screenFrame = BScreen().Frame();
|
||||||
|
BMessage decoratorSettings;
|
||||||
|
fDownloadWindow->GetDecoratorSettings(&decoratorSettings);
|
||||||
|
float borderWidth = 0;
|
||||||
|
if (decoratorSettings.FindFloat("border width", &borderWidth) != B_OK)
|
||||||
|
borderWidth = 5;
|
||||||
|
fDownloadWindow->MoveTo(screenFrame.Width() - fDownloadWindow->Frame().Width() - borderWidth,
|
||||||
|
screenFrame.Height() - fDownloadWindow->Frame().Height() - borderWidth);
|
||||||
|
}
|
||||||
|
fSettingsWindow = new SettingsWindow(settingsWindowFrame, fSettings);
|
||||||
|
|
||||||
|
BWebPage::SetDownloadListener(BMessenger(fDownloadWindow));
|
||||||
|
|
||||||
|
fInitialized = true;
|
||||||
|
|
||||||
|
int32 pagesCreated = 0;
|
||||||
|
bool fullscreen = false;
|
||||||
|
if (fLaunchRefsMessage) {
|
||||||
|
_RefsReceived(fLaunchRefsMessage, &pagesCreated, &fullscreen);
|
||||||
|
delete fLaunchRefsMessage;
|
||||||
|
fLaunchRefsMessage = NULL;
|
||||||
|
}
|
||||||
|
if (pagesCreated == 0)
|
||||||
|
_CreateNewWindow("", fullscreen);
|
||||||
|
|
||||||
|
PostMessage(PRELOAD_BROWSING_HISTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case PRELOAD_BROWSING_HISTORY:
|
||||||
|
// Accessing the default instance will load the history from disk.
|
||||||
|
BrowsingHistory::DefaultInstance();
|
||||||
|
break;
|
||||||
|
case B_SILENT_RELAUNCH:
|
||||||
|
_CreateNewPage("");
|
||||||
|
break;
|
||||||
|
case NEW_WINDOW: {
|
||||||
|
BString url;
|
||||||
|
if (message->FindString("url", &url) != B_OK)
|
||||||
|
break;
|
||||||
|
_CreateNewWindow(url);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NEW_TAB: {
|
||||||
|
BrowserWindow* window;
|
||||||
|
if (message->FindPointer("window", reinterpret_cast<void**>(&window)) != B_OK)
|
||||||
|
break;
|
||||||
|
BString url;
|
||||||
|
message->FindString("url", &url);
|
||||||
|
bool select = false;
|
||||||
|
message->FindBool("select", &select);
|
||||||
|
_CreateNewTab(window, url, select);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WINDOW_OPENED:
|
||||||
|
fWindowCount++;
|
||||||
|
fDownloadWindow->SetMinimizeOnClose(false);
|
||||||
|
break;
|
||||||
|
case WINDOW_CLOSED:
|
||||||
|
fWindowCount--;
|
||||||
|
message->FindRect("window frame", &fLastWindowFrame);
|
||||||
|
if (fWindowCount <= 0)
|
||||||
|
PostMessage(B_QUIT_REQUESTED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SHOW_DOWNLOAD_WINDOW:
|
||||||
|
_ShowWindow(message, fDownloadWindow);
|
||||||
|
break;
|
||||||
|
case SHOW_SETTINGS_WINDOW:
|
||||||
|
_ShowWindow(message, fSettingsWindow);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BApplication::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::RefsReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
if (!fInitialized) {
|
||||||
|
delete fLaunchRefsMessage;
|
||||||
|
fLaunchRefsMessage = new BMessage(*message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_RefsReceived(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowserApp::QuitRequested()
|
||||||
|
{
|
||||||
|
if (fDownloadWindow->DownloadsInProgress()) {
|
||||||
|
BAlert* alert = new BAlert("Downloads in progress",
|
||||||
|
"There are still downloads in progress, do you really want to "
|
||||||
|
"quit WebPositive now?", "Quit", "Continue downloads");
|
||||||
|
int32 choice = alert->Go();
|
||||||
|
if (choice == 1) {
|
||||||
|
if (fWindowCount == 0) {
|
||||||
|
if (fDownloadWindow->Lock()) {
|
||||||
|
fDownloadWindow->SetWorkspaces(1 << current_workspace());
|
||||||
|
if (fDownloadWindow->IsHidden())
|
||||||
|
fDownloadWindow->Show();
|
||||||
|
else
|
||||||
|
fDownloadWindow->Activate();
|
||||||
|
fDownloadWindow->SetMinimizeOnClose(true);
|
||||||
|
fDownloadWindow->Unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; BWindow* window = WindowAt(i); i++) {
|
||||||
|
BrowserWindow* webWindow = dynamic_cast<BrowserWindow*>(window);
|
||||||
|
if (!webWindow)
|
||||||
|
continue;
|
||||||
|
if (!webWindow->Lock())
|
||||||
|
continue;
|
||||||
|
if (webWindow->QuitRequested()) {
|
||||||
|
fLastWindowFrame = webWindow->WindowFrame();
|
||||||
|
webWindow->Quit();
|
||||||
|
i--;
|
||||||
|
} else {
|
||||||
|
webWindow->Unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BWebPage::ShutdownOnce();
|
||||||
|
|
||||||
|
fSettings->SetValue("window frame", fLastWindowFrame);
|
||||||
|
if (fDownloadWindow->Lock()) {
|
||||||
|
fSettings->SetValue("downloads window frame", fDownloadWindow->Frame());
|
||||||
|
fSettings->SetValue("show downloads", !fDownloadWindow->IsHidden());
|
||||||
|
fDownloadWindow->Unlock();
|
||||||
|
}
|
||||||
|
if (fSettingsWindow->Lock()) {
|
||||||
|
fSettings->SetValue("settings window frame", fSettingsWindow->Frame());
|
||||||
|
fSettingsWindow->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
BMessage cookieArchive;
|
||||||
|
if (fCookieJar != NULL && fCookieJar->Archive(&cookieArchive) == B_OK)
|
||||||
|
fCookies->SetValue("cookies", cookieArchive);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::_RefsReceived(BMessage* message, int32* _pagesCreated,
|
||||||
|
bool* _fullscreen)
|
||||||
|
{
|
||||||
|
int32 pagesCreated = 0;
|
||||||
|
|
||||||
|
bool fullscreen;
|
||||||
|
if (message->FindBool("fullscreen", &fullscreen) != B_OK)
|
||||||
|
fullscreen = false;
|
||||||
|
|
||||||
|
entry_ref ref;
|
||||||
|
for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) {
|
||||||
|
BEntry entry(&ref, true);
|
||||||
|
if (!entry.Exists())
|
||||||
|
continue;
|
||||||
|
BPath path;
|
||||||
|
if (entry.GetPath(&path) != B_OK)
|
||||||
|
continue;
|
||||||
|
BString url;
|
||||||
|
url << path.Path();
|
||||||
|
_CreateNewPage(url, fullscreen);
|
||||||
|
pagesCreated++;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString url;
|
||||||
|
for (int32 i = 0; message->FindString("url", i, &url) == B_OK; i++) {
|
||||||
|
_CreateNewPage(url, fullscreen);
|
||||||
|
pagesCreated++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pagesCreated != NULL)
|
||||||
|
*_pagesCreated = pagesCreated;
|
||||||
|
if (_fullscreen != NULL)
|
||||||
|
*_fullscreen = fullscreen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::_CreateNewPage(const BString& url, bool fullscreen)
|
||||||
|
{
|
||||||
|
uint32 workspace = 1 << current_workspace();
|
||||||
|
|
||||||
|
bool loadedInWindowOnCurrentWorkspace = false;
|
||||||
|
for (int i = 0; BWindow* window = WindowAt(i); i++) {
|
||||||
|
BrowserWindow* webWindow = dynamic_cast<BrowserWindow*>(window);
|
||||||
|
if (!webWindow)
|
||||||
|
continue;
|
||||||
|
if (webWindow->Lock()) {
|
||||||
|
if (webWindow->Workspaces() & workspace) {
|
||||||
|
if (webWindow->IsBlankTab()) {
|
||||||
|
if (url.Length() != 0)
|
||||||
|
webWindow->CurrentWebView()->LoadURL(url);
|
||||||
|
} else
|
||||||
|
webWindow->CreateNewTab(url, true);
|
||||||
|
webWindow->Activate();
|
||||||
|
webWindow->CurrentWebView()->MakeFocus(true);
|
||||||
|
loadedInWindowOnCurrentWorkspace = true;
|
||||||
|
}
|
||||||
|
webWindow->Unlock();
|
||||||
|
}
|
||||||
|
if (loadedInWindowOnCurrentWorkspace)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_CreateNewWindow(url, fullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::_CreateNewWindow(const BString& url, bool fullscreen)
|
||||||
|
{
|
||||||
|
// Offset the window frame unless this is the first window created in the
|
||||||
|
// session.
|
||||||
|
if (fWindowCount > 0)
|
||||||
|
fLastWindowFrame.OffsetBy(20, 20);
|
||||||
|
if (!BScreen().Frame().Contains(fLastWindowFrame))
|
||||||
|
fLastWindowFrame.OffsetTo(50, 50);
|
||||||
|
|
||||||
|
BrowserWindow* window = new BrowserWindow(fLastWindowFrame, fSettings,
|
||||||
|
url);
|
||||||
|
if (fullscreen)
|
||||||
|
window->ToggleFullscreen();
|
||||||
|
window->Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::_CreateNewTab(BrowserWindow* window, const BString& url,
|
||||||
|
bool select)
|
||||||
|
{
|
||||||
|
if (!window->Lock())
|
||||||
|
return;
|
||||||
|
window->CreateNewTab(url, select);
|
||||||
|
window->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowserApp::_ShowWindow(const BMessage* message, BWindow* window)
|
||||||
|
{
|
||||||
|
BAutolock _(window);
|
||||||
|
uint32 workspaces;
|
||||||
|
if (message->FindUInt32("workspaces", &workspaces) == B_OK)
|
||||||
|
window->SetWorkspaces(workspaces);
|
||||||
|
if (window->IsHidden())
|
||||||
|
window->Show();
|
||||||
|
else
|
||||||
|
window->Activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int, char**)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
new BrowserApp();
|
||||||
|
be_app->Run();
|
||||||
|
delete be_app;
|
||||||
|
} catch (...) {
|
||||||
|
debugger("Exception caught.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Ryan Leavengood <[email protected]>
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef BROWSER_APP_H
|
||||||
|
#define BROWSER_APP_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <Catalog.h>
|
||||||
|
#include <Rect.h>
|
||||||
|
|
||||||
|
class BNetworkCookieJar;
|
||||||
|
class DownloadWindow;
|
||||||
|
class BrowserWindow;
|
||||||
|
class SettingsMessage;
|
||||||
|
class SettingsWindow;
|
||||||
|
|
||||||
|
|
||||||
|
class BrowserApp : public BApplication {
|
||||||
|
public:
|
||||||
|
BrowserApp();
|
||||||
|
virtual ~BrowserApp();
|
||||||
|
|
||||||
|
virtual void AboutRequested();
|
||||||
|
virtual void ArgvReceived(int32 agrc, char** argv);
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
virtual void RefsReceived(BMessage* message);
|
||||||
|
virtual void ReadyToRun();
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _RefsReceived(BMessage* message,
|
||||||
|
int32* pagesCreated = NULL,
|
||||||
|
bool* fullscreen = NULL);
|
||||||
|
void _CreateNewPage(const BString& url,
|
||||||
|
bool fullscreen = false);
|
||||||
|
void _CreateNewWindow(const BString& url,
|
||||||
|
bool fullscreen = false);
|
||||||
|
void _CreateNewTab(BrowserWindow* window,
|
||||||
|
const BString& url, bool select);
|
||||||
|
void _ShowWindow(const BMessage* message,
|
||||||
|
BWindow* window);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fWindowCount;
|
||||||
|
BRect fLastWindowFrame;
|
||||||
|
BMessage* fLaunchRefsMessage;
|
||||||
|
bool fInitialized;
|
||||||
|
|
||||||
|
SettingsMessage* fSettings;
|
||||||
|
SettingsMessage* fCookies;
|
||||||
|
BNetworkCookieJar* fCookieJar;
|
||||||
|
|
||||||
|
DownloadWindow* fDownloadWindow;
|
||||||
|
SettingsWindow* fSettingsWindow;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern const char* kApplicationSignature;
|
||||||
|
extern const char* kApplicationName;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BROWSER_APP_H
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,257 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007 Ryan Leavengood <[email protected]>
|
||||||
|
* Copyright (C) 2009 Maxime Simon <[email protected]>
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef BROWSER_WINDOW_H
|
||||||
|
#define BROWSER_WINDOW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "WebWindow.h"
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
class BButton;
|
||||||
|
class BCheckBox;
|
||||||
|
class BDirectory;
|
||||||
|
class BFile;
|
||||||
|
class BLayoutItem;
|
||||||
|
class BMenu;
|
||||||
|
class BMenuItem;
|
||||||
|
class BMessageRunner;
|
||||||
|
class BPath;
|
||||||
|
class BStatusBar;
|
||||||
|
class BStringView;
|
||||||
|
class BTextControl;
|
||||||
|
class BWebView;
|
||||||
|
class IconButton;
|
||||||
|
class SettingsMessage;
|
||||||
|
class TabManager;
|
||||||
|
class URLInputGroup;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INTERFACE_ELEMENT_MENU = 1 << 0,
|
||||||
|
INTERFACE_ELEMENT_TABS = 1 << 1,
|
||||||
|
INTERFACE_ELEMENT_NAVIGATION = 1 << 2,
|
||||||
|
INTERFACE_ELEMENT_STATUS = 1 << 3,
|
||||||
|
|
||||||
|
INTERFACE_ELEMENT_ALL = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
|
enum NewPagePolicy {
|
||||||
|
OpenBlankPage = 0,
|
||||||
|
OpenStartPage = 1,
|
||||||
|
OpenSearchPage = 2,
|
||||||
|
CloneCurrentPage = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NEW_WINDOW = 'nwnd',
|
||||||
|
NEW_TAB = 'ntab',
|
||||||
|
WINDOW_OPENED = 'wndo',
|
||||||
|
WINDOW_CLOSED = 'wndc',
|
||||||
|
SHOW_DOWNLOAD_WINDOW = 'sdwd',
|
||||||
|
SHOW_SETTINGS_WINDOW = 'sswd'
|
||||||
|
};
|
||||||
|
|
||||||
|
#define INTEGRATE_MENU_INTO_TAB_BAR 0
|
||||||
|
|
||||||
|
|
||||||
|
class BrowserWindow : public BWebWindow {
|
||||||
|
public:
|
||||||
|
BrowserWindow(BRect frame,
|
||||||
|
SettingsMessage* appSettings,
|
||||||
|
const BString& url,
|
||||||
|
uint32 interfaceElements
|
||||||
|
= INTERFACE_ELEMENT_ALL,
|
||||||
|
BWebView* webView = NULL);
|
||||||
|
virtual ~BrowserWindow();
|
||||||
|
|
||||||
|
virtual void DispatchMessage(BMessage* message,
|
||||||
|
BHandler* target);
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
virtual void MenusBeginning();
|
||||||
|
|
||||||
|
virtual void Zoom(BPoint origin, float width, float height);
|
||||||
|
virtual void ScreenChanged(BRect screenSize,
|
||||||
|
color_space format);
|
||||||
|
virtual void WorkspacesChanged(uint32 oldWorkspaces,
|
||||||
|
uint32 newWorkspaces);
|
||||||
|
|
||||||
|
virtual void SetCurrentWebView(BWebView* view);
|
||||||
|
|
||||||
|
bool IsBlankTab() const;
|
||||||
|
void CreateNewTab(const BString& url, bool select,
|
||||||
|
BWebView* webView = 0);
|
||||||
|
|
||||||
|
BRect WindowFrame() const;
|
||||||
|
|
||||||
|
void ToggleFullscreen();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// WebPage notification API implementations
|
||||||
|
virtual void NavigationRequested(const BString& url,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void NewWindowRequested(const BString& url,
|
||||||
|
bool primaryAction);
|
||||||
|
virtual void CloseWindowRequested(BWebView* view);
|
||||||
|
virtual void NewPageCreated(BWebView* view,
|
||||||
|
BRect windowFrame, bool modalDialog,
|
||||||
|
bool resizable, bool activate);
|
||||||
|
virtual void LoadNegotiating(const BString& url,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void LoadCommitted(const BString& url,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void LoadProgress(float progress, BWebView* view);
|
||||||
|
virtual void LoadFailed(const BString& url, BWebView* view);
|
||||||
|
virtual void LoadFinished(const BString& url,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void MainDocumentError(const BString& failingURL,
|
||||||
|
const BString& localizedDescription,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void TitleChanged(const BString& title,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void IconReceived(const BBitmap* icon,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void ResizeRequested(float width, float height,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void SetToolBarsVisible(bool flag, BWebView* view);
|
||||||
|
virtual void SetStatusBarVisible(bool flag, BWebView* view);
|
||||||
|
virtual void SetMenuBarVisible(bool flag, BWebView* view);
|
||||||
|
virtual void SetResizable(bool flag, BWebView* view);
|
||||||
|
virtual void StatusChanged(const BString& status,
|
||||||
|
BWebView* view);
|
||||||
|
virtual void NavigationCapabilitiesChanged(
|
||||||
|
bool canGoBackward, bool canGoForward,
|
||||||
|
bool canStop, BWebView* view);
|
||||||
|
virtual void UpdateGlobalHistory(const BString& url);
|
||||||
|
virtual bool AuthenticationChallenge(BString message,
|
||||||
|
BString& inOutUser, BString& inOutPassword,
|
||||||
|
bool& inOutRememberCredentials,
|
||||||
|
uint32 failureCount, BWebView* view);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _UpdateTitle(const BString &title);
|
||||||
|
void _UpdateTabGroupVisibility();
|
||||||
|
bool _TabGroupShouldBeVisible() const;
|
||||||
|
void _ShutdownTab(int32 index);
|
||||||
|
void _TabChanged(int32 index);
|
||||||
|
|
||||||
|
status_t _BookmarkPath(BPath& path) const;
|
||||||
|
void _CreateBookmark();
|
||||||
|
void _ShowBookmarks();
|
||||||
|
bool _CheckBookmarkExists(BDirectory& directory,
|
||||||
|
const BString& fileName,
|
||||||
|
const BString& url) const;
|
||||||
|
bool _ReadURLAttr(BFile& bookmarkFile,
|
||||||
|
BString& url) const;
|
||||||
|
void _AddBookmarkURLsRecursively(
|
||||||
|
BDirectory& directory,
|
||||||
|
BMessage* message,
|
||||||
|
uint32& addedCount) const;
|
||||||
|
|
||||||
|
void _SetPageIcon(BWebView* view,
|
||||||
|
const BBitmap* icon);
|
||||||
|
|
||||||
|
void _UpdateHistoryMenu();
|
||||||
|
void _UpdateClipboardItems();
|
||||||
|
|
||||||
|
bool _ShowPage(BWebView* view);
|
||||||
|
|
||||||
|
void _ToggleFullscreen();
|
||||||
|
void _ResizeToScreen();
|
||||||
|
void _SetAutoHideInterfaceInFullscreen(bool doIt);
|
||||||
|
void _CheckAutoHideInterface();
|
||||||
|
void _ShowInterface(bool show);
|
||||||
|
void _ShowProgressBar(bool);
|
||||||
|
void _InvokeButtonVisibly(BButton* button);
|
||||||
|
|
||||||
|
BString _NewTabURL(bool isNewWindow) const;
|
||||||
|
BString _SmartURLHandler(const BString& url) const;
|
||||||
|
|
||||||
|
void _HandlePageSourceResult(
|
||||||
|
const BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BMenu* fHistoryMenu;
|
||||||
|
int32 fHistoryMenuFixedItemCount;
|
||||||
|
|
||||||
|
BMenuItem* fCutMenuItem;
|
||||||
|
BMenuItem* fCopyMenuItem;
|
||||||
|
BMenuItem* fPasteMenuItem;
|
||||||
|
BMenuItem* fFindPreviousMenuItem;
|
||||||
|
BMenuItem* fFindNextMenuItem;
|
||||||
|
BMenuItem* fZoomTextOnlyMenuItem;
|
||||||
|
BMenuItem* fFullscreenItem;
|
||||||
|
BMenuItem* fBackMenuItem;
|
||||||
|
BMenuItem* fForwardMenuItem;
|
||||||
|
|
||||||
|
IconButton* fBackButton;
|
||||||
|
IconButton* fForwardButton;
|
||||||
|
IconButton* fStopButton;
|
||||||
|
IconButton* fHomeButton;
|
||||||
|
URLInputGroup* fURLInputGroup;
|
||||||
|
BStringView* fStatusText;
|
||||||
|
BStatusBar* fLoadingProgressBar;
|
||||||
|
|
||||||
|
BLayoutItem* fMenuGroup;
|
||||||
|
BLayoutItem* fTabGroup;
|
||||||
|
BLayoutItem* fNavigationGroup;
|
||||||
|
BLayoutItem* fFindGroup;
|
||||||
|
BLayoutItem* fStatusGroup;
|
||||||
|
BLayoutItem* fToggleFullscreenButton;
|
||||||
|
|
||||||
|
BTextControl* fFindTextControl;
|
||||||
|
BButton* fFindPreviousButton;
|
||||||
|
BButton* fFindNextButton;
|
||||||
|
BButton* fFindCloseButton;
|
||||||
|
BCheckBox* fFindCaseSensitiveCheckBox;
|
||||||
|
TabManager* fTabManager;
|
||||||
|
|
||||||
|
bool fIsFullscreen;
|
||||||
|
bool fInterfaceVisible;
|
||||||
|
BRect fNonFullscreenWindowFrame;
|
||||||
|
BMessageRunner* fPulseRunner;
|
||||||
|
uint32 fVisibleInterfaceElements;
|
||||||
|
bigtime_t fLastMouseMovedTime;
|
||||||
|
BPoint fLastMousePos;
|
||||||
|
|
||||||
|
// cached settings
|
||||||
|
SettingsMessage* fAppSettings;
|
||||||
|
bool fZoomTextOnly;
|
||||||
|
bool fShowTabsIfSinglePageOpen;
|
||||||
|
bool fAutoHideInterfaceInFullscreenMode;
|
||||||
|
bool fAutoHidePointer;
|
||||||
|
uint32 fNewWindowPolicy;
|
||||||
|
uint32 fNewTabPolicy;
|
||||||
|
BString fStartPageURL;
|
||||||
|
BString fSearchPageURL;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BROWSER_WINDOW_H
|
||||||
|
|
||||||
@@ -0,0 +1,381 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BrowsingHistory.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Autolock.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Message.h>
|
||||||
|
#include <Path.h>
|
||||||
|
|
||||||
|
#include "BrowserApp.h"
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistoryItem::BrowsingHistoryItem(const BString& url)
|
||||||
|
:
|
||||||
|
fURL(url),
|
||||||
|
fDateTime(BDateTime::CurrentDateTime(B_LOCAL_TIME)),
|
||||||
|
fInvokationCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistoryItem::BrowsingHistoryItem(const BrowsingHistoryItem& other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistoryItem::BrowsingHistoryItem(const BMessage* archive)
|
||||||
|
{
|
||||||
|
if (!archive)
|
||||||
|
return;
|
||||||
|
BMessage dateTimeArchive;
|
||||||
|
if (archive->FindMessage("date time", &dateTimeArchive) == B_OK)
|
||||||
|
fDateTime = BDateTime(&dateTimeArchive);
|
||||||
|
archive->FindString("url", &fURL);
|
||||||
|
archive->FindUInt32("invokations", &fInvokationCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistoryItem::~BrowsingHistoryItem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BrowsingHistoryItem::Archive(BMessage* archive) const
|
||||||
|
{
|
||||||
|
if (!archive)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
BMessage dateTimeArchive;
|
||||||
|
status_t status = fDateTime.Archive(&dateTimeArchive);
|
||||||
|
if (status == B_OK)
|
||||||
|
status = archive->AddMessage("date time", &dateTimeArchive);
|
||||||
|
if (status == B_OK)
|
||||||
|
status = archive->AddString("url", fURL.String());
|
||||||
|
if (status == B_OK)
|
||||||
|
status = archive->AddUInt32("invokations", fInvokationCount);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistoryItem&
|
||||||
|
BrowsingHistoryItem::operator=(const BrowsingHistoryItem& other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
fURL = other.fURL;
|
||||||
|
fDateTime = other.fDateTime;
|
||||||
|
fInvokationCount = other.fInvokationCount;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistoryItem::operator==(const BrowsingHistoryItem& other) const
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return fURL == other.fURL && fDateTime == other.fDateTime
|
||||||
|
&& fInvokationCount == other.fInvokationCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistoryItem::operator!=(const BrowsingHistoryItem& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistoryItem::operator<(const BrowsingHistoryItem& other) const
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return fDateTime < other.fDateTime || fURL < other.fURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistoryItem::operator<=(const BrowsingHistoryItem& other) const
|
||||||
|
{
|
||||||
|
return (*this == other) || (*this < other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistoryItem::operator>(const BrowsingHistoryItem& other) const
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return fDateTime > other.fDateTime || fURL > other.fURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistoryItem::operator>=(const BrowsingHistoryItem& other) const
|
||||||
|
{
|
||||||
|
return (*this == other) || (*this > other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowsingHistoryItem::Invoked()
|
||||||
|
{
|
||||||
|
// Eventually, we may overflow...
|
||||||
|
uint32 count = fInvokationCount + 1;
|
||||||
|
if (count > fInvokationCount)
|
||||||
|
fInvokationCount = count;
|
||||||
|
fDateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BrowsingHistory
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistory
|
||||||
|
BrowsingHistory::sDefaultInstance;
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistory::BrowsingHistory()
|
||||||
|
:
|
||||||
|
BLocker("browsing history"),
|
||||||
|
fHistoryItems(64),
|
||||||
|
fMaxHistoryItemAge(7),
|
||||||
|
fSettingsLoaded(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistory::~BrowsingHistory()
|
||||||
|
{
|
||||||
|
_SaveSettings();
|
||||||
|
_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ BrowsingHistory*
|
||||||
|
BrowsingHistory::DefaultInstance()
|
||||||
|
{
|
||||||
|
if (sDefaultInstance.Lock()) {
|
||||||
|
sDefaultInstance._LoadSettings();
|
||||||
|
sDefaultInstance.Unlock();
|
||||||
|
}
|
||||||
|
return &sDefaultInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistory::AddItem(const BrowsingHistoryItem& item)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
return _AddItem(item, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BrowsingHistory::BrowsingHistory::CountItems() const
|
||||||
|
{
|
||||||
|
BAutolock _(const_cast<BrowsingHistory*>(this));
|
||||||
|
|
||||||
|
return fHistoryItems.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BrowsingHistoryItem
|
||||||
|
BrowsingHistory::HistoryItemAt(int32 index) const
|
||||||
|
{
|
||||||
|
BAutolock _(const_cast<BrowsingHistory*>(this));
|
||||||
|
|
||||||
|
BrowsingHistoryItem* existingItem = reinterpret_cast<BrowsingHistoryItem*>(
|
||||||
|
fHistoryItems.ItemAt(index));
|
||||||
|
if (!existingItem)
|
||||||
|
return BrowsingHistoryItem(BString());
|
||||||
|
|
||||||
|
return BrowsingHistoryItem(*existingItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowsingHistory::Clear()
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
_Clear();
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowsingHistory::SetMaxHistoryItemAge(int32 days)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
if (fMaxHistoryItemAge != days) {
|
||||||
|
fMaxHistoryItemAge = days;
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BrowsingHistory::MaxHistoryItemAge() const
|
||||||
|
{
|
||||||
|
return fMaxHistoryItemAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowsingHistory::_Clear()
|
||||||
|
{
|
||||||
|
int32 count = CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BrowsingHistoryItem* item = reinterpret_cast<BrowsingHistoryItem*>(
|
||||||
|
fHistoryItems.ItemAtFast(i));
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
fHistoryItems.MakeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistory::_AddItem(const BrowsingHistoryItem& item, bool internal)
|
||||||
|
{
|
||||||
|
int32 count = CountItems();
|
||||||
|
int32 insertionIndex = count;
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BrowsingHistoryItem* existingItem
|
||||||
|
= reinterpret_cast<BrowsingHistoryItem*>(
|
||||||
|
fHistoryItems.ItemAtFast(i));
|
||||||
|
if (item.URL() == existingItem->URL()) {
|
||||||
|
if (!internal) {
|
||||||
|
existingItem->Invoked();
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (item < *existingItem)
|
||||||
|
insertionIndex = i;
|
||||||
|
}
|
||||||
|
BrowsingHistoryItem* newItem = new(std::nothrow) BrowsingHistoryItem(item);
|
||||||
|
if (!newItem || !fHistoryItems.AddItem(newItem, insertionIndex)) {
|
||||||
|
delete newItem;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!internal) {
|
||||||
|
newItem->Invoked();
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowsingHistory::_LoadSettings()
|
||||||
|
{
|
||||||
|
if (fSettingsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fSettingsLoaded = true;
|
||||||
|
|
||||||
|
BFile settingsFile;
|
||||||
|
if (_OpenSettingsFile(settingsFile, B_READ_ONLY)) {
|
||||||
|
BMessage settingsArchive;
|
||||||
|
settingsArchive.Unflatten(&settingsFile);
|
||||||
|
if (settingsArchive.FindInt32("max history item age",
|
||||||
|
&fMaxHistoryItemAge) != B_OK) {
|
||||||
|
fMaxHistoryItemAge = 7;
|
||||||
|
}
|
||||||
|
BDateTime oldestAllowedDateTime
|
||||||
|
= BDateTime::CurrentDateTime(B_LOCAL_TIME);
|
||||||
|
oldestAllowedDateTime.Date().AddDays(-fMaxHistoryItemAge);
|
||||||
|
|
||||||
|
BMessage historyItemArchive;
|
||||||
|
for (int32 i = 0; settingsArchive.FindMessage("history item", i,
|
||||||
|
&historyItemArchive) == B_OK; i++) {
|
||||||
|
BrowsingHistoryItem item(&historyItemArchive);
|
||||||
|
if (oldestAllowedDateTime < item.DateTime())
|
||||||
|
_AddItem(item, true);
|
||||||
|
historyItemArchive.MakeEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BrowsingHistory::_SaveSettings()
|
||||||
|
{
|
||||||
|
BFile settingsFile;
|
||||||
|
if (_OpenSettingsFile(settingsFile,
|
||||||
|
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) {
|
||||||
|
BMessage settingsArchive;
|
||||||
|
settingsArchive.AddInt32("max history item age", fMaxHistoryItemAge);
|
||||||
|
BMessage historyItemArchive;
|
||||||
|
int32 count = CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BrowsingHistoryItem item = HistoryItemAt(i);
|
||||||
|
if (item.Archive(&historyItemArchive) != B_OK)
|
||||||
|
break;
|
||||||
|
if (settingsArchive.AddMessage("history item",
|
||||||
|
&historyItemArchive) != B_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
historyItemArchive.MakeEmpty();
|
||||||
|
}
|
||||||
|
settingsArchive.Flatten(&settingsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BrowsingHistory::_OpenSettingsFile(BFile& file, uint32 mode)
|
||||||
|
{
|
||||||
|
BPath path;
|
||||||
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK
|
||||||
|
|| path.Append(kApplicationName) != B_OK
|
||||||
|
|| path.Append("BrowsingHistory") != B_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return file.SetTo(path.Path(), mode) == B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef BROWSING_HISTORY_H
|
||||||
|
#define BROWSING_HISTORY_H
|
||||||
|
|
||||||
|
#include "DateTime.h"
|
||||||
|
#include <List.h>
|
||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
|
class BFile;
|
||||||
|
class BString;
|
||||||
|
|
||||||
|
|
||||||
|
class BrowsingHistoryItem {
|
||||||
|
public:
|
||||||
|
BrowsingHistoryItem(const BString& url);
|
||||||
|
BrowsingHistoryItem(
|
||||||
|
const BrowsingHistoryItem& other);
|
||||||
|
BrowsingHistoryItem(const BMessage* archive);
|
||||||
|
~BrowsingHistoryItem();
|
||||||
|
|
||||||
|
status_t Archive(BMessage* archive) const;
|
||||||
|
|
||||||
|
BrowsingHistoryItem& operator=(const BrowsingHistoryItem& other);
|
||||||
|
|
||||||
|
bool operator==(
|
||||||
|
const BrowsingHistoryItem& other) const;
|
||||||
|
bool operator!=(
|
||||||
|
const BrowsingHistoryItem& other) const;
|
||||||
|
bool operator<(
|
||||||
|
const BrowsingHistoryItem& other) const;
|
||||||
|
bool operator<=(
|
||||||
|
const BrowsingHistoryItem& other) const;
|
||||||
|
bool operator>(
|
||||||
|
const BrowsingHistoryItem& other) const;
|
||||||
|
bool operator>=(
|
||||||
|
const BrowsingHistoryItem& other) const;
|
||||||
|
|
||||||
|
const BString& URL() const { return fURL; }
|
||||||
|
const BDateTime& DateTime() const { return fDateTime; }
|
||||||
|
uint32 InvokationCount() const {
|
||||||
|
return fInvokationCount; }
|
||||||
|
void Invoked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fURL;
|
||||||
|
BDateTime fDateTime;
|
||||||
|
uint32 fInvokationCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BrowsingHistory : public BLocker {
|
||||||
|
public:
|
||||||
|
static BrowsingHistory* DefaultInstance();
|
||||||
|
|
||||||
|
bool AddItem(const BrowsingHistoryItem& item);
|
||||||
|
|
||||||
|
// Should Lock() the object when using these in some loop or so:
|
||||||
|
int32 CountItems() const;
|
||||||
|
BrowsingHistoryItem HistoryItemAt(int32 index) const;
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
void SetMaxHistoryItemAge(int32 days);
|
||||||
|
int32 MaxHistoryItemAge() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BrowsingHistory();
|
||||||
|
virtual ~BrowsingHistory();
|
||||||
|
|
||||||
|
void _Clear();
|
||||||
|
bool _AddItem(const BrowsingHistoryItem& item,
|
||||||
|
bool invoke);
|
||||||
|
|
||||||
|
void _LoadSettings();
|
||||||
|
void _SaveSettings();
|
||||||
|
bool _OpenSettingsFile(BFile& file, uint32 mode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BList fHistoryItems;
|
||||||
|
int32 fMaxHistoryItemAge;
|
||||||
|
|
||||||
|
static BrowsingHistory sDefaultInstance;
|
||||||
|
bool fSettingsLoaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BROWSING_HISTORY_H
|
||||||
|
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CredentialsStorage.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Autolock.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Message.h>
|
||||||
|
#include <Path.h>
|
||||||
|
|
||||||
|
#include "BrowserApp.h"
|
||||||
|
|
||||||
|
|
||||||
|
Credentials::Credentials()
|
||||||
|
:
|
||||||
|
fUsername(),
|
||||||
|
fPassword()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Credentials::Credentials(const BString& username, const BString& password)
|
||||||
|
:
|
||||||
|
fUsername(username),
|
||||||
|
fPassword(password)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Credentials::Credentials(const Credentials& other)
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Credentials::Credentials(const BMessage* archive)
|
||||||
|
{
|
||||||
|
if (archive == NULL)
|
||||||
|
return;
|
||||||
|
archive->FindString("username", &fUsername);
|
||||||
|
archive->FindString("password", &fPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Credentials::~Credentials()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Credentials::Archive(BMessage* archive) const
|
||||||
|
{
|
||||||
|
if (archive == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
status_t status = archive->AddString("username", fUsername);
|
||||||
|
if (status == B_OK)
|
||||||
|
status = archive->AddString("password", fPassword);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Credentials&
|
||||||
|
Credentials::operator=(const Credentials& other)
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
fUsername = other.fUsername;
|
||||||
|
fPassword = other.fPassword;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Credentials::operator==(const Credentials& other) const
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return fUsername == other.fUsername && fPassword == other.fPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Credentials::operator!=(const Credentials& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BString&
|
||||||
|
Credentials::Username() const
|
||||||
|
{
|
||||||
|
return fUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BString&
|
||||||
|
Credentials::Password() const
|
||||||
|
{
|
||||||
|
return fPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - CredentialsStorage
|
||||||
|
|
||||||
|
|
||||||
|
CredentialsStorage
|
||||||
|
CredentialsStorage::sPersistentInstance(true);
|
||||||
|
|
||||||
|
|
||||||
|
CredentialsStorage
|
||||||
|
CredentialsStorage::sSessionInstance(false);
|
||||||
|
|
||||||
|
|
||||||
|
CredentialsStorage::CredentialsStorage(bool persistent)
|
||||||
|
:
|
||||||
|
BLocker(persistent ? "persistent credential storage"
|
||||||
|
: "credential storage"),
|
||||||
|
fCredentialMap(),
|
||||||
|
fSettingsLoaded(false),
|
||||||
|
fPersistent(persistent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CredentialsStorage::~CredentialsStorage()
|
||||||
|
{
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ CredentialsStorage*
|
||||||
|
CredentialsStorage::SessionInstance()
|
||||||
|
{
|
||||||
|
return &sSessionInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ CredentialsStorage*
|
||||||
|
CredentialsStorage::PersistentInstance()
|
||||||
|
{
|
||||||
|
if (sPersistentInstance.Lock()) {
|
||||||
|
sPersistentInstance._LoadSettings();
|
||||||
|
sPersistentInstance.Unlock();
|
||||||
|
}
|
||||||
|
return &sPersistentInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CredentialsStorage::Contains(const HashKeyString& key)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
return fCredentialMap.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CredentialsStorage::PutCredentials(const HashKeyString& key,
|
||||||
|
const Credentials& credentials)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
return fCredentialMap.Put(key, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Credentials
|
||||||
|
CredentialsStorage::GetCredentials(const HashKeyString& key)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
return fCredentialMap.Get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CredentialsStorage::_LoadSettings()
|
||||||
|
{
|
||||||
|
if (!fPersistent || fSettingsLoaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fSettingsLoaded = true;
|
||||||
|
|
||||||
|
BFile settingsFile;
|
||||||
|
if (_OpenSettingsFile(settingsFile, B_READ_ONLY)) {
|
||||||
|
BMessage settingsArchive;
|
||||||
|
settingsArchive.Unflatten(&settingsFile);
|
||||||
|
BMessage credentialsArchive;
|
||||||
|
for (int32 i = 0; settingsArchive.FindMessage("credentials", i,
|
||||||
|
&credentialsArchive) == B_OK; i++) {
|
||||||
|
BString key;
|
||||||
|
if (credentialsArchive.FindString("key", &key) == B_OK) {
|
||||||
|
Credentials credentials(&credentialsArchive);
|
||||||
|
fCredentialMap.Put(key, credentials);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CredentialsStorage::_SaveSettings() const
|
||||||
|
{
|
||||||
|
BFile settingsFile;
|
||||||
|
if (_OpenSettingsFile(settingsFile,
|
||||||
|
B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY)) {
|
||||||
|
BMessage settingsArchive;
|
||||||
|
BMessage credentialsArchive;
|
||||||
|
CredentialMap::Iterator iterator = fCredentialMap.GetIterator();
|
||||||
|
while (iterator.HasNext()) {
|
||||||
|
const CredentialMap::Entry& entry = iterator.Next();
|
||||||
|
if (entry.value.Archive(&credentialsArchive) != B_OK
|
||||||
|
|| credentialsArchive.AddString("key",
|
||||||
|
entry.key.value) != B_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (settingsArchive.AddMessage("credentials",
|
||||||
|
&credentialsArchive) != B_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
credentialsArchive.MakeEmpty();
|
||||||
|
}
|
||||||
|
settingsArchive.Flatten(&settingsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CredentialsStorage::_OpenSettingsFile(BFile& file, uint32 mode) const
|
||||||
|
{
|
||||||
|
BPath path;
|
||||||
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK
|
||||||
|
|| path.Append(kApplicationName) != B_OK
|
||||||
|
|| path.Append("CredentialsStorage") != B_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return file.SetTo(path.Path(), mode) == B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef CREDENTIAL_STORAGE_H
|
||||||
|
#define CREDENTIAL_STORAGE_H
|
||||||
|
|
||||||
|
#include "HashKeys.h"
|
||||||
|
#include "HashMap.h"
|
||||||
|
#include <Locker.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BFile;
|
||||||
|
class BMessage;
|
||||||
|
class BString;
|
||||||
|
|
||||||
|
|
||||||
|
class Credentials {
|
||||||
|
public:
|
||||||
|
Credentials();
|
||||||
|
Credentials(const BString& username,
|
||||||
|
const BString& password);
|
||||||
|
Credentials(
|
||||||
|
const Credentials& other);
|
||||||
|
Credentials(const BMessage* archive);
|
||||||
|
~Credentials();
|
||||||
|
|
||||||
|
status_t Archive(BMessage* archive) const;
|
||||||
|
|
||||||
|
Credentials& operator=(const Credentials& other);
|
||||||
|
|
||||||
|
bool operator==(const Credentials& other) const;
|
||||||
|
bool operator!=(const Credentials& other) const;
|
||||||
|
|
||||||
|
const BString& Username() const;
|
||||||
|
const BString& Password() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fUsername;
|
||||||
|
BString fPassword;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CredentialsStorage : public BLocker {
|
||||||
|
public:
|
||||||
|
static CredentialsStorage* SessionInstance();
|
||||||
|
static CredentialsStorage* PersistentInstance();
|
||||||
|
|
||||||
|
bool Contains(const HashKeyString& key);
|
||||||
|
status_t PutCredentials(const HashKeyString& key,
|
||||||
|
const Credentials& credentials);
|
||||||
|
Credentials GetCredentials(const HashKeyString& key);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CredentialsStorage(bool persistent);
|
||||||
|
virtual ~CredentialsStorage();
|
||||||
|
|
||||||
|
void _LoadSettings();
|
||||||
|
void _SaveSettings() const;
|
||||||
|
bool _OpenSettingsFile(BFile& file,
|
||||||
|
uint32 mode) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef HashMap<HashKeyString, Credentials> CredentialMap;
|
||||||
|
CredentialMap fCredentialMap;
|
||||||
|
|
||||||
|
static CredentialsStorage sPersistentInstance;
|
||||||
|
static CredentialsStorage sSessionInstance;
|
||||||
|
bool fSettingsLoaded;
|
||||||
|
bool fPersistent;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CREDENTIAL_STORAGE_H
|
||||||
|
|
||||||
@@ -0,0 +1,838 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DownloadProgressView.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Alert.h>
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <Clipboard.h>
|
||||||
|
#include <Directory.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <GroupLayoutBuilder.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <NodeInfo.h>
|
||||||
|
#include <NodeMonitor.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <Roster.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
#include <StatusBar.h>
|
||||||
|
#include <StringView.h>
|
||||||
|
|
||||||
|
#include "WebDownload.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
#include "StringForSize.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OPEN_DOWNLOAD = 'opdn',
|
||||||
|
RESTART_DOWNLOAD = 'rsdn',
|
||||||
|
CANCEL_DOWNLOAD = 'cndn',
|
||||||
|
REMOVE_DOWNLOAD = 'rmdn',
|
||||||
|
COPY_URL_TO_CLIPBOARD = 'curl',
|
||||||
|
OPEN_CONTAINING_FOLDER = 'opfd',
|
||||||
|
};
|
||||||
|
|
||||||
|
const bigtime_t kMaxUpdateInterval = 100000LL;
|
||||||
|
const bigtime_t kSpeedReferenceInterval = 500000LL;
|
||||||
|
const bigtime_t kShowSpeedInterval = 8000000LL;
|
||||||
|
const bigtime_t kShowEstimatedFinishInterval = 4000000LL;
|
||||||
|
|
||||||
|
bigtime_t DownloadProgressView::sLastEstimatedFinishSpeedToggleTime = -1;
|
||||||
|
bool DownloadProgressView::sShowSpeed = true;
|
||||||
|
|
||||||
|
|
||||||
|
class IconView : public BView {
|
||||||
|
public:
|
||||||
|
IconView(const BEntry& entry)
|
||||||
|
:
|
||||||
|
BView("Download icon", B_WILL_DRAW),
|
||||||
|
fIconBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32),
|
||||||
|
fDimmedIcon(false)
|
||||||
|
{
|
||||||
|
SetDrawingMode(B_OP_OVER);
|
||||||
|
SetTo(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
IconView()
|
||||||
|
:
|
||||||
|
BView("Download icon", B_WILL_DRAW),
|
||||||
|
fIconBitmap(BRect(0, 0, 31, 31), 0, B_RGBA32),
|
||||||
|
fDimmedIcon(false)
|
||||||
|
{
|
||||||
|
SetDrawingMode(B_OP_OVER);
|
||||||
|
memset(fIconBitmap.Bits(), 0, fIconBitmap.BitsLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
IconView(BMessage* archive)
|
||||||
|
:
|
||||||
|
BView("Download icon", B_WILL_DRAW),
|
||||||
|
fIconBitmap(archive),
|
||||||
|
fDimmedIcon(true)
|
||||||
|
{
|
||||||
|
SetDrawingMode(B_OP_OVER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTo(const BEntry& entry)
|
||||||
|
{
|
||||||
|
BNode node(&entry);
|
||||||
|
BNodeInfo info(&node);
|
||||||
|
info.GetTrackerIcon(&fIconBitmap, B_LARGE_ICON);
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetIconDimmed(bool iconDimmed)
|
||||||
|
{
|
||||||
|
if (fDimmedIcon != iconDimmed) {
|
||||||
|
fDimmedIcon = iconDimmed;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsIconDimmed() const
|
||||||
|
{
|
||||||
|
return fDimmedIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t SaveSettings(BMessage* archive)
|
||||||
|
{
|
||||||
|
return fIconBitmap.Archive(archive);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AttachedToWindow()
|
||||||
|
{
|
||||||
|
SetViewColor(Parent()->ViewColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
if (fDimmedIcon) {
|
||||||
|
SetDrawingMode(B_OP_ALPHA);
|
||||||
|
SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
SetHighColor(0, 0, 0, 100);
|
||||||
|
}
|
||||||
|
DrawBitmapAsync(&fIconBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(fIconBitmap.Bounds().Width(), fIconBitmap.Bounds().Height());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BBitmap fIconBitmap;
|
||||||
|
bool fDimmedIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SmallButton : public BButton {
|
||||||
|
public:
|
||||||
|
SmallButton(const char* label, BMessage* message = NULL)
|
||||||
|
:
|
||||||
|
BButton(label, message)
|
||||||
|
{
|
||||||
|
BFont font;
|
||||||
|
GetFont(&font);
|
||||||
|
float size = ceilf(font.Size() * 0.8);
|
||||||
|
font.SetSize(max_c(8, size));
|
||||||
|
SetFont(&font, B_FONT_SIZE);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DownloadProgressView
|
||||||
|
|
||||||
|
|
||||||
|
DownloadProgressView::DownloadProgressView(BWebDownload* download)
|
||||||
|
:
|
||||||
|
BGroupView(B_HORIZONTAL, 8),
|
||||||
|
fDownload(download),
|
||||||
|
fURL(download->URL()),
|
||||||
|
fPath(download->Path())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownloadProgressView::DownloadProgressView(const BMessage* archive)
|
||||||
|
:
|
||||||
|
BGroupView(B_HORIZONTAL, 8),
|
||||||
|
fDownload(NULL),
|
||||||
|
fURL(),
|
||||||
|
fPath()
|
||||||
|
{
|
||||||
|
const char* string;
|
||||||
|
if (archive->FindString("path", &string) == B_OK)
|
||||||
|
fPath.SetTo(string);
|
||||||
|
if (archive->FindString("url", &string) == B_OK)
|
||||||
|
fURL = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadProgressView::Init(BMessage* archive)
|
||||||
|
{
|
||||||
|
fCurrentSize = 0;
|
||||||
|
fExpectedSize = 0;
|
||||||
|
fLastUpdateTime = 0;
|
||||||
|
fBytesPerSecond = 0.0;
|
||||||
|
for (size_t i = 0; i < kBytesPerSecondSlots; i++)
|
||||||
|
fBytesPerSecondSlot[i] = 0.0;
|
||||||
|
fCurrentBytesPerSecondSlot = 0;
|
||||||
|
fLastSpeedReferenceSize = 0;
|
||||||
|
fEstimatedFinishReferenceSize = 0;
|
||||||
|
|
||||||
|
fProcessStartTime = fLastSpeedReferenceTime = fEstimatedFinishReferenceTime
|
||||||
|
= system_time();
|
||||||
|
|
||||||
|
SetViewColor(245, 245, 245);
|
||||||
|
SetFlags(Flags() | B_FULL_UPDATE_ON_RESIZE | B_WILL_DRAW);
|
||||||
|
|
||||||
|
if (archive) {
|
||||||
|
fStatusBar = new BStatusBar("download progress", fPath.Leaf());
|
||||||
|
float value;
|
||||||
|
if (archive->FindFloat("value", &value) == B_OK)
|
||||||
|
fStatusBar->SetTo(value);
|
||||||
|
} else
|
||||||
|
fStatusBar = new BStatusBar("download progress", "Download");
|
||||||
|
fStatusBar->SetMaxValue(100);
|
||||||
|
fStatusBar->SetBarHeight(12);
|
||||||
|
|
||||||
|
// fPath is only valid when constructed from archive (fDownload == NULL)
|
||||||
|
BEntry entry(fPath.Path());
|
||||||
|
|
||||||
|
if (archive) {
|
||||||
|
if (!entry.Exists())
|
||||||
|
fIconView = new IconView(archive);
|
||||||
|
else
|
||||||
|
fIconView = new IconView(entry);
|
||||||
|
} else
|
||||||
|
fIconView = new IconView();
|
||||||
|
|
||||||
|
if (!fDownload && (fStatusBar->CurrentValue() < 100 || !entry.Exists()))
|
||||||
|
fTopButton = new SmallButton("Restart", new BMessage(RESTART_DOWNLOAD));
|
||||||
|
else {
|
||||||
|
fTopButton = new SmallButton("Open", new BMessage(OPEN_DOWNLOAD));
|
||||||
|
fTopButton->SetEnabled(fDownload == NULL);
|
||||||
|
}
|
||||||
|
if (fDownload)
|
||||||
|
fBottomButton = new SmallButton("Cancel", new BMessage(CANCEL_DOWNLOAD));
|
||||||
|
else {
|
||||||
|
fBottomButton = new SmallButton("Remove", new BMessage(REMOVE_DOWNLOAD));
|
||||||
|
fBottomButton->SetEnabled(fDownload == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fInfoView = new BStringView("info view", "");
|
||||||
|
|
||||||
|
BGroupLayout* layout = GroupLayout();
|
||||||
|
layout->SetInsets(8, 5, 5, 6);
|
||||||
|
layout->AddView(fIconView);
|
||||||
|
BView* verticalGroup = BGroupLayoutBuilder(B_VERTICAL, 3)
|
||||||
|
.Add(fStatusBar)
|
||||||
|
.Add(fInfoView)
|
||||||
|
.TopView()
|
||||||
|
;
|
||||||
|
verticalGroup->SetViewColor(ViewColor());
|
||||||
|
layout->AddView(verticalGroup);
|
||||||
|
verticalGroup = BGroupLayoutBuilder(B_VERTICAL, 3)
|
||||||
|
.Add(fTopButton)
|
||||||
|
.Add(fBottomButton)
|
||||||
|
.TopView()
|
||||||
|
;
|
||||||
|
verticalGroup->SetViewColor(ViewColor());
|
||||||
|
layout->AddView(verticalGroup);
|
||||||
|
|
||||||
|
BFont font;
|
||||||
|
fInfoView->GetFont(&font);
|
||||||
|
float fontSize = font.Size() * 0.8f;
|
||||||
|
font.SetSize(max_c(8.0f, fontSize));
|
||||||
|
fInfoView->SetFont(&font, B_FONT_SIZE);
|
||||||
|
fInfoView->SetHighColor(tint_color(fInfoView->LowColor(),
|
||||||
|
B_DARKEN_4_TINT));
|
||||||
|
fInfoView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DownloadProgressView::SaveSettings(BMessage* archive)
|
||||||
|
{
|
||||||
|
if (!archive)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
status_t ret = archive->AddString("path", fPath.Path());
|
||||||
|
if (ret == B_OK)
|
||||||
|
ret = archive->AddString("url", fURL.String());
|
||||||
|
if (ret == B_OK)
|
||||||
|
ret = archive->AddFloat("value", fStatusBar->CurrentValue());
|
||||||
|
if (ret == B_OK)
|
||||||
|
ret = fIconView->SaveSettings(archive);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::AttachedToWindow()
|
||||||
|
{
|
||||||
|
if (fDownload) {
|
||||||
|
fDownload->SetProgressListener(BMessenger(this));
|
||||||
|
// Will start node monitor upon receiving the B_DOWNLOAD_STARTED
|
||||||
|
// message.
|
||||||
|
} else {
|
||||||
|
BEntry entry(fPath.Path());
|
||||||
|
if (entry.Exists())
|
||||||
|
_StartNodeMonitor(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
fTopButton->SetTarget(this);
|
||||||
|
fBottomButton->SetTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::DetachedFromWindow()
|
||||||
|
{
|
||||||
|
_StopNodeMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::AllAttached()
|
||||||
|
{
|
||||||
|
SetViewColor(B_TRANSPARENT_COLOR);
|
||||||
|
SetLowColor(245, 245, 245);
|
||||||
|
SetHighColor(tint_color(LowColor(), B_DARKEN_1_TINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect bounds(Bounds());
|
||||||
|
bounds.bottom--;
|
||||||
|
FillRect(bounds, B_SOLID_LOW);
|
||||||
|
bounds.bottom++;
|
||||||
|
StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case B_DOWNLOAD_STARTED:
|
||||||
|
{
|
||||||
|
BString path;
|
||||||
|
if (message->FindString("path", &path) != B_OK)
|
||||||
|
break;
|
||||||
|
fPath.SetTo(path);
|
||||||
|
BEntry entry(fPath.Path());
|
||||||
|
fIconView->SetTo(entry);
|
||||||
|
fStatusBar->Reset(fPath.Leaf());
|
||||||
|
_StartNodeMonitor(entry);
|
||||||
|
|
||||||
|
// Immediately switch to speed display whenever a new download
|
||||||
|
// starts.
|
||||||
|
sShowSpeed = true;
|
||||||
|
sLastEstimatedFinishSpeedToggleTime
|
||||||
|
= fProcessStartTime = fLastSpeedReferenceTime
|
||||||
|
= fEstimatedFinishReferenceTime = system_time();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B_DOWNLOAD_PROGRESS:
|
||||||
|
{
|
||||||
|
int64 currentSize;
|
||||||
|
int64 expectedSize;
|
||||||
|
if (message->FindInt64("current size", ¤tSize) == B_OK
|
||||||
|
&& message->FindInt64("expected size", &expectedSize) == B_OK) {
|
||||||
|
_UpdateStatus(currentSize, expectedSize);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B_DOWNLOAD_REMOVED:
|
||||||
|
// TODO: This is a bit asymetric. The removed notification
|
||||||
|
// arrives here, but it would be nicer if it arrived
|
||||||
|
// at the window...
|
||||||
|
Window()->PostMessage(message);
|
||||||
|
break;
|
||||||
|
case OPEN_DOWNLOAD:
|
||||||
|
{
|
||||||
|
// TODO: In case of executable files, ask the user first!
|
||||||
|
entry_ref ref;
|
||||||
|
status_t status = get_ref_for_path(fPath.Path(), &ref);
|
||||||
|
if (status == B_OK)
|
||||||
|
status = be_roster->Launch(&ref);
|
||||||
|
if (status != B_OK && status != B_ALREADY_RUNNING) {
|
||||||
|
BAlert* alert = new BAlert("Open download error",
|
||||||
|
"The download could not be opened.", "OK");
|
||||||
|
alert->Go(NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RESTART_DOWNLOAD:
|
||||||
|
BWebPage::RequestDownload(fURL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CANCEL_DOWNLOAD:
|
||||||
|
fDownload->Cancel();
|
||||||
|
DownloadCanceled();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REMOVE_DOWNLOAD:
|
||||||
|
{
|
||||||
|
Window()->PostMessage(SAVE_SETTINGS);
|
||||||
|
RemoveSelf();
|
||||||
|
delete this;
|
||||||
|
// TOAST!
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case B_NODE_MONITOR:
|
||||||
|
{
|
||||||
|
int32 opCode;
|
||||||
|
if (message->FindInt32("opcode", &opCode) != B_OK)
|
||||||
|
break;
|
||||||
|
switch (opCode) {
|
||||||
|
case B_ENTRY_REMOVED:
|
||||||
|
fIconView->SetIconDimmed(true);
|
||||||
|
DownloadCanceled();
|
||||||
|
break;
|
||||||
|
case B_ENTRY_MOVED:
|
||||||
|
{
|
||||||
|
// Follow the entry to the new location
|
||||||
|
dev_t device;
|
||||||
|
ino_t directory;
|
||||||
|
const char* name;
|
||||||
|
if (message->FindInt32("device",
|
||||||
|
reinterpret_cast<int32*>(&device)) != B_OK
|
||||||
|
|| message->FindInt64("to directory",
|
||||||
|
reinterpret_cast<int64*>(&directory)) != B_OK
|
||||||
|
|| message->FindString("name", &name) != B_OK
|
||||||
|
|| strlen(name) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Construct the BEntry and update fPath
|
||||||
|
entry_ref ref(device, directory, name);
|
||||||
|
BEntry entry(&ref);
|
||||||
|
if (entry.GetPath(&fPath) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Find out if the directory is the Trash for this
|
||||||
|
// volume
|
||||||
|
char trashPath[B_PATH_NAME_LENGTH];
|
||||||
|
if (find_directory(B_TRASH_DIRECTORY, device, false,
|
||||||
|
trashPath, B_PATH_NAME_LENGTH) == B_OK) {
|
||||||
|
BPath trashDirectory(trashPath);
|
||||||
|
BPath parentDirectory;
|
||||||
|
fPath.GetParent(&parentDirectory);
|
||||||
|
if (parentDirectory == trashDirectory) {
|
||||||
|
// The entry was moved into the Trash.
|
||||||
|
// If the download is still in progress,
|
||||||
|
// cancel it.
|
||||||
|
if (fDownload)
|
||||||
|
fDownload->Cancel();
|
||||||
|
fIconView->SetIconDimmed(true);
|
||||||
|
DownloadCanceled();
|
||||||
|
break;
|
||||||
|
} else if (fIconView->IsIconDimmed()) {
|
||||||
|
// Maybe it was moved out of the trash.
|
||||||
|
fIconView->SetIconDimmed(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inform download of the new path
|
||||||
|
if (fDownload)
|
||||||
|
fDownload->HasMovedTo(fPath);
|
||||||
|
|
||||||
|
float value = fStatusBar->CurrentValue();
|
||||||
|
fStatusBar->Reset(name);
|
||||||
|
fStatusBar->SetTo(value);
|
||||||
|
Window()->PostMessage(SAVE_SETTINGS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B_ATTR_CHANGED:
|
||||||
|
{
|
||||||
|
BEntry entry(fPath.Path());
|
||||||
|
fIconView->SetIconDimmed(false);
|
||||||
|
fIconView->SetTo(entry);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context menu messages
|
||||||
|
case COPY_URL_TO_CLIPBOARD:
|
||||||
|
if (be_clipboard->Lock()) {
|
||||||
|
BMessage* data = be_clipboard->Data();
|
||||||
|
if (data != NULL) {
|
||||||
|
be_clipboard->Clear();
|
||||||
|
data->AddData("text/plain", B_MIME_TYPE, fURL.String(),
|
||||||
|
fURL.Length());
|
||||||
|
}
|
||||||
|
be_clipboard->Commit();
|
||||||
|
be_clipboard->Unlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPEN_CONTAINING_FOLDER:
|
||||||
|
if (fPath.InitCheck() == B_OK) {
|
||||||
|
BPath containingFolder;
|
||||||
|
if (fPath.GetParent(&containingFolder) != B_OK)
|
||||||
|
break;
|
||||||
|
BEntry entry(containingFolder.Path());
|
||||||
|
if (!entry.Exists())
|
||||||
|
break;
|
||||||
|
entry_ref ref;
|
||||||
|
if (entry.GetRef(&ref) != B_OK)
|
||||||
|
break;
|
||||||
|
be_roster->Launch(&ref);
|
||||||
|
|
||||||
|
// Use Tracker scripting and select the download pose
|
||||||
|
// in the window.
|
||||||
|
// TODO: We should somehow get the window that just openend.
|
||||||
|
// Using the name like this is broken when there are multiple
|
||||||
|
// windows open with this name. Also Tracker does not scroll
|
||||||
|
// to this entry.
|
||||||
|
BString windowName = ref.name;
|
||||||
|
BString fullWindowName = containingFolder.Path();
|
||||||
|
|
||||||
|
BMessenger trackerMessenger("application/x-vnd.Be-TRAK");
|
||||||
|
if (trackerMessenger.IsValid()
|
||||||
|
&& get_ref_for_path(fPath.Path(), &ref) == B_OK) {
|
||||||
|
// We need to wait a bit until the folder is open.
|
||||||
|
// TODO: This is also too fragile... we should be able
|
||||||
|
// to wait for the roster message.
|
||||||
|
snooze(250000);
|
||||||
|
int32 tries = 2;
|
||||||
|
while (tries > 0) {
|
||||||
|
BMessage selectionCommand(B_SET_PROPERTY);
|
||||||
|
selectionCommand.AddSpecifier("Selection");
|
||||||
|
selectionCommand.AddSpecifier("Poses");
|
||||||
|
selectionCommand.AddSpecifier("Window",
|
||||||
|
windowName.String());
|
||||||
|
selectionCommand.AddRef("data", &ref);
|
||||||
|
BMessage reply;
|
||||||
|
trackerMessenger.SendMessage(&selectionCommand, &reply);
|
||||||
|
int32 error;
|
||||||
|
if (reply.FindInt32("error", &error) != B_OK
|
||||||
|
|| error == B_OK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
windowName = fullWindowName;
|
||||||
|
tries--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BGroupView::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::ShowContextMenu(BPoint screenWhere)
|
||||||
|
{
|
||||||
|
screenWhere += BPoint(2, 2);
|
||||||
|
|
||||||
|
BPopUpMenu* contextMenu = new BPopUpMenu("download context");
|
||||||
|
BMenuItem* copyURL = new BMenuItem("Copy URL to clipboard",
|
||||||
|
new BMessage(COPY_URL_TO_CLIPBOARD));
|
||||||
|
copyURL->SetEnabled(fURL.Length() > 0);
|
||||||
|
contextMenu->AddItem(copyURL);
|
||||||
|
BMenuItem* openFolder = new BMenuItem("Open containing folder",
|
||||||
|
new BMessage(OPEN_CONTAINING_FOLDER));
|
||||||
|
contextMenu->AddItem(openFolder);
|
||||||
|
|
||||||
|
contextMenu->SetTargetForItems(this);
|
||||||
|
contextMenu->Go(screenWhere, true, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BWebDownload*
|
||||||
|
DownloadProgressView::Download() const
|
||||||
|
{
|
||||||
|
return fDownload;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BString&
|
||||||
|
DownloadProgressView::URL() const
|
||||||
|
{
|
||||||
|
return fURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadProgressView::IsMissing() const
|
||||||
|
{
|
||||||
|
return fIconView->IsIconDimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadProgressView::IsFinished() const
|
||||||
|
{
|
||||||
|
return !fDownload && fStatusBar->CurrentValue() == 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::DownloadFinished()
|
||||||
|
{
|
||||||
|
fDownload = NULL;
|
||||||
|
if (fExpectedSize == -1) {
|
||||||
|
fStatusBar->SetTo(100.0);
|
||||||
|
fExpectedSize = fCurrentSize;
|
||||||
|
}
|
||||||
|
fTopButton->SetEnabled(true);
|
||||||
|
fBottomButton->SetLabel("Remove");
|
||||||
|
fBottomButton->SetMessage(new BMessage(REMOVE_DOWNLOAD));
|
||||||
|
fBottomButton->SetEnabled(true);
|
||||||
|
fInfoView->SetText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::DownloadCanceled()
|
||||||
|
{
|
||||||
|
fDownload = NULL;
|
||||||
|
fTopButton->SetLabel("Restart");
|
||||||
|
fTopButton->SetMessage(new BMessage(RESTART_DOWNLOAD));
|
||||||
|
fTopButton->SetEnabled(true);
|
||||||
|
fBottomButton->SetLabel("Remove");
|
||||||
|
fBottomButton->SetMessage(new BMessage(REMOVE_DOWNLOAD));
|
||||||
|
fBottomButton->SetEnabled(true);
|
||||||
|
fInfoView->SetText("");
|
||||||
|
fPath.Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ void
|
||||||
|
DownloadProgressView::SpeedVersusEstimatedFinishTogglePulse()
|
||||||
|
{
|
||||||
|
bigtime_t now = system_time();
|
||||||
|
if (sShowSpeed
|
||||||
|
&& sLastEstimatedFinishSpeedToggleTime + kShowSpeedInterval
|
||||||
|
<= now) {
|
||||||
|
sShowSpeed = false;
|
||||||
|
sLastEstimatedFinishSpeedToggleTime = now;
|
||||||
|
} else if (!sShowSpeed
|
||||||
|
&& sLastEstimatedFinishSpeedToggleTime
|
||||||
|
+ kShowEstimatedFinishInterval <= now) {
|
||||||
|
sShowSpeed = true;
|
||||||
|
sLastEstimatedFinishSpeedToggleTime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::_UpdateStatus(off_t currentSize, off_t expectedSize)
|
||||||
|
{
|
||||||
|
fCurrentSize = currentSize;
|
||||||
|
fExpectedSize = expectedSize;
|
||||||
|
|
||||||
|
fStatusBar->SetTo(100.0 * currentSize / expectedSize);
|
||||||
|
|
||||||
|
bigtime_t currentTime = system_time();
|
||||||
|
if ((currentTime - fLastUpdateTime) > kMaxUpdateInterval) {
|
||||||
|
fLastUpdateTime = currentTime;
|
||||||
|
|
||||||
|
if (currentTime >= fLastSpeedReferenceTime + kSpeedReferenceInterval) {
|
||||||
|
// update current speed every kSpeedReferenceInterval
|
||||||
|
fCurrentBytesPerSecondSlot
|
||||||
|
= (fCurrentBytesPerSecondSlot + 1) % kBytesPerSecondSlots;
|
||||||
|
fBytesPerSecondSlot[fCurrentBytesPerSecondSlot]
|
||||||
|
= (double)(currentSize - fLastSpeedReferenceSize)
|
||||||
|
* 1000000LL / (currentTime - fLastSpeedReferenceTime);
|
||||||
|
fLastSpeedReferenceSize = currentSize;
|
||||||
|
fLastSpeedReferenceTime = currentTime;
|
||||||
|
fBytesPerSecond = 0.0;
|
||||||
|
size_t count = 0;
|
||||||
|
for (size_t i = 0; i < kBytesPerSecondSlots; i++) {
|
||||||
|
if (fBytesPerSecondSlot[i] != 0.0) {
|
||||||
|
fBytesPerSecond += fBytesPerSecondSlot[i];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0)
|
||||||
|
fBytesPerSecond /= count;
|
||||||
|
}
|
||||||
|
_UpdateStatusText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::_UpdateStatusText()
|
||||||
|
{
|
||||||
|
fInfoView->SetText("");
|
||||||
|
BString buffer;
|
||||||
|
if (sShowSpeed && fBytesPerSecond != 0.0) {
|
||||||
|
// Draw speed info
|
||||||
|
char sizeBuffer[128];
|
||||||
|
buffer = "(";
|
||||||
|
// Get strings for current and expected size and remove the unit
|
||||||
|
// from the current size string if it's the same as the expected
|
||||||
|
// size unit.
|
||||||
|
BString currentSize = string_for_size((double)fCurrentSize, sizeBuffer,
|
||||||
|
sizeof(sizeBuffer));
|
||||||
|
BString expectedSize = string_for_size((double)fExpectedSize, sizeBuffer,
|
||||||
|
sizeof(sizeBuffer));
|
||||||
|
int currentSizeUnitPos = currentSize.FindLast(' ');
|
||||||
|
int expectedSizeUnitPos = expectedSize.FindLast(' ');
|
||||||
|
if (currentSizeUnitPos >= 0 && expectedSizeUnitPos >= 0
|
||||||
|
&& strcmp(currentSize.String() + currentSizeUnitPos,
|
||||||
|
expectedSize.String() + expectedSizeUnitPos) == 0) {
|
||||||
|
currentSize.Truncate(currentSizeUnitPos);
|
||||||
|
}
|
||||||
|
buffer << currentSize;
|
||||||
|
buffer << " of ";
|
||||||
|
buffer << expectedSize;
|
||||||
|
buffer << ", ";
|
||||||
|
buffer << string_for_size(fBytesPerSecond, sizeBuffer,
|
||||||
|
sizeof(sizeBuffer));
|
||||||
|
buffer << "/s)";
|
||||||
|
float stringWidth = fInfoView->StringWidth(buffer.String());
|
||||||
|
if (stringWidth < fInfoView->Bounds().Width())
|
||||||
|
fInfoView->SetText(buffer.String());
|
||||||
|
else {
|
||||||
|
// complete string too wide, try with shorter version
|
||||||
|
buffer << string_for_size(fBytesPerSecond, sizeBuffer,
|
||||||
|
sizeof(sizeBuffer));
|
||||||
|
buffer << "/s";
|
||||||
|
stringWidth = fInfoView->StringWidth(buffer.String());
|
||||||
|
if (stringWidth < fInfoView->Bounds().Width())
|
||||||
|
fInfoView->SetText(buffer.String());
|
||||||
|
}
|
||||||
|
} else if (!sShowSpeed && fCurrentSize < fExpectedSize) {
|
||||||
|
double totalBytesPerSecond = (double)(fCurrentSize
|
||||||
|
- fEstimatedFinishReferenceSize)
|
||||||
|
* 1000000LL / (system_time() - fEstimatedFinishReferenceTime);
|
||||||
|
double secondsRemaining = (fExpectedSize - fCurrentSize)
|
||||||
|
/ totalBytesPerSecond;
|
||||||
|
time_t now = (time_t)real_time_clock();
|
||||||
|
time_t finishTime = (time_t)(now + secondsRemaining);
|
||||||
|
|
||||||
|
tm _time;
|
||||||
|
tm* time = localtime_r(&finishTime, &_time);
|
||||||
|
int32 year = time->tm_year + 1900;
|
||||||
|
|
||||||
|
char timeText[32];
|
||||||
|
time_t secondsPerDay = 24 * 60 * 60;
|
||||||
|
// TODO: Localization of time string...
|
||||||
|
if (now < finishTime - secondsPerDay) {
|
||||||
|
// process is going to take more than a day!
|
||||||
|
sprintf(timeText, "%0*d:%0*d %0*d/%0*d/%ld",
|
||||||
|
2, time->tm_hour, 2, time->tm_min,
|
||||||
|
2, time->tm_mon + 1, 2, time->tm_mday, year);
|
||||||
|
} else {
|
||||||
|
sprintf(timeText, "%0*d:%0*d",
|
||||||
|
2, time->tm_hour, 2, time->tm_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
BString buffer1("Finish: ");
|
||||||
|
buffer1 << timeText;
|
||||||
|
finishTime -= now;
|
||||||
|
time = gmtime(&finishTime);
|
||||||
|
|
||||||
|
BString buffer2;
|
||||||
|
if (finishTime > secondsPerDay) {
|
||||||
|
int64 days = finishTime / secondsPerDay;
|
||||||
|
if (days == 1)
|
||||||
|
buffer2 << "Over 1 day";
|
||||||
|
else
|
||||||
|
buffer2 << "Over " << days << " days";
|
||||||
|
} else if (finishTime > 60 * 60) {
|
||||||
|
int64 hours = finishTime / (60 * 60);
|
||||||
|
if (hours == 1)
|
||||||
|
buffer2 << "Over 1 hour";
|
||||||
|
else
|
||||||
|
buffer2 << "Over " << hours << " hours";
|
||||||
|
} else if (finishTime > 60) {
|
||||||
|
int64 minutes = finishTime / 60;
|
||||||
|
if (minutes == 1)
|
||||||
|
buffer2 << "Over 1 minute";
|
||||||
|
else
|
||||||
|
buffer2 << minutes << " minutes";
|
||||||
|
} else {
|
||||||
|
if (finishTime == 1)
|
||||||
|
buffer2 << "1 second";
|
||||||
|
else
|
||||||
|
buffer2 << finishTime << " seconds";
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer2 << " left";
|
||||||
|
|
||||||
|
buffer = "(";
|
||||||
|
buffer << buffer1 << " - " << buffer2 << ")";
|
||||||
|
|
||||||
|
float stringWidth = fInfoView->StringWidth(buffer.String());
|
||||||
|
if (stringWidth < fInfoView->Bounds().Width())
|
||||||
|
fInfoView->SetText(buffer.String());
|
||||||
|
else {
|
||||||
|
// complete string too wide, try with shorter version
|
||||||
|
buffer = "(";
|
||||||
|
buffer << buffer1 << ")";
|
||||||
|
stringWidth = fInfoView->StringWidth(buffer.String());
|
||||||
|
if (stringWidth < fInfoView->Bounds().Width())
|
||||||
|
fInfoView->SetText(buffer.String());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::_StartNodeMonitor(const BEntry& entry)
|
||||||
|
{
|
||||||
|
node_ref nref;
|
||||||
|
if (entry.GetNodeRef(&nref) == B_OK)
|
||||||
|
watch_node(&nref, B_WATCH_ALL, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadProgressView::_StopNodeMonitor()
|
||||||
|
{
|
||||||
|
stop_watching(this);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef DOWNLOAD_PROGRESS_VIEW_H
|
||||||
|
#define DOWNLOAD_PROGRESS_VIEW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <GroupView.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
class BEntry;
|
||||||
|
class BStatusBar;
|
||||||
|
class BStringView;
|
||||||
|
class BWebDownload;
|
||||||
|
class IconView;
|
||||||
|
class SmallButton;
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SAVE_SETTINGS = 'svst'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadProgressView : public BGroupView {
|
||||||
|
public:
|
||||||
|
DownloadProgressView(BWebDownload* download);
|
||||||
|
DownloadProgressView(const BMessage* archive);
|
||||||
|
|
||||||
|
bool Init(BMessage* archive = NULL);
|
||||||
|
|
||||||
|
status_t SaveSettings(BMessage* archive);
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
virtual void DetachedFromWindow();
|
||||||
|
virtual void AllAttached();
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
void ShowContextMenu(BPoint screenWhere);
|
||||||
|
|
||||||
|
BWebDownload* Download() const;
|
||||||
|
const BString& URL() const;
|
||||||
|
bool IsMissing() const;
|
||||||
|
bool IsFinished() const;
|
||||||
|
|
||||||
|
void DownloadFinished();
|
||||||
|
void DownloadCanceled();
|
||||||
|
|
||||||
|
static void SpeedVersusEstimatedFinishTogglePulse();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _UpdateStatus(off_t currentSize,
|
||||||
|
off_t expectedSize);
|
||||||
|
void _UpdateStatusText();
|
||||||
|
void _StartNodeMonitor(const BEntry& entry);
|
||||||
|
void _StopNodeMonitor();
|
||||||
|
|
||||||
|
private:
|
||||||
|
IconView* fIconView;
|
||||||
|
BStatusBar* fStatusBar;
|
||||||
|
BStringView* fInfoView;
|
||||||
|
SmallButton* fTopButton;
|
||||||
|
SmallButton* fBottomButton;
|
||||||
|
BWebDownload* fDownload;
|
||||||
|
BString fURL;
|
||||||
|
BPath fPath;
|
||||||
|
|
||||||
|
off_t fCurrentSize;
|
||||||
|
off_t fExpectedSize;
|
||||||
|
off_t fLastSpeedReferenceSize;
|
||||||
|
off_t fEstimatedFinishReferenceSize;
|
||||||
|
bigtime_t fLastUpdateTime;
|
||||||
|
bigtime_t fLastSpeedReferenceTime;
|
||||||
|
bigtime_t fProcessStartTime;
|
||||||
|
bigtime_t fLastSpeedUpdateTime;
|
||||||
|
bigtime_t fEstimatedFinishReferenceTime;
|
||||||
|
static const size_t kBytesPerSecondSlots = 10;
|
||||||
|
size_t fCurrentBytesPerSecondSlot;
|
||||||
|
double fBytesPerSecondSlot[kBytesPerSecondSlots];
|
||||||
|
double fBytesPerSecond;
|
||||||
|
|
||||||
|
static bigtime_t sLastEstimatedFinishSpeedToggleTime;
|
||||||
|
static bool sShowSpeed;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DOWNLOAD_PROGRESS_VIEW_H
|
||||||
@@ -0,0 +1,573 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DownloadWindow.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Alert.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <GroupLayout.h>
|
||||||
|
#include <GroupLayoutBuilder.h>
|
||||||
|
#include <MenuBar.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <Roster.h>
|
||||||
|
#include <ScrollView.h>
|
||||||
|
#include <SeparatorView.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
|
||||||
|
#include "BrowserApp.h"
|
||||||
|
#include "BrowserWindow.h"
|
||||||
|
#include "DownloadProgressView.h"
|
||||||
|
#include "SettingsKeys.h"
|
||||||
|
#include "SettingsMessage.h"
|
||||||
|
#include "WebDownload.h"
|
||||||
|
#include "WebPage.h"
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
INIT = 'init',
|
||||||
|
OPEN_DOWNLOADS_FOLDER = 'odnf',
|
||||||
|
REMOVE_FINISHED_DOWNLOADS = 'rmfd',
|
||||||
|
REMOVE_MISSING_DOWNLOADS = 'rmmd'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadsContainerView : public BGroupView {
|
||||||
|
public:
|
||||||
|
DownloadsContainerView()
|
||||||
|
:
|
||||||
|
BGroupView(B_VERTICAL, 0.0)
|
||||||
|
{
|
||||||
|
SetFlags(Flags() | B_PULSE_NEEDED);
|
||||||
|
SetViewColor(245, 245, 245);
|
||||||
|
AddChild(BSpaceLayoutItem::CreateGlue());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
BSize minSize = BGroupView::MinSize();
|
||||||
|
return BSize(minSize.width, 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Pulse()
|
||||||
|
{
|
||||||
|
DownloadProgressView::SpeedVersusEstimatedFinishTogglePulse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DoLayout()
|
||||||
|
{
|
||||||
|
BGroupView::DoLayout();
|
||||||
|
if (BScrollBar* scrollBar = ScrollBar(B_VERTICAL)) {
|
||||||
|
BSize minSize = BGroupView::MinSize();
|
||||||
|
float height = Bounds().Height();
|
||||||
|
float max = minSize.height - height;
|
||||||
|
scrollBar->SetRange(0, max);
|
||||||
|
if (minSize.height > 0)
|
||||||
|
scrollBar->SetProportion(height / minSize.height);
|
||||||
|
else
|
||||||
|
scrollBar->SetProportion(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadContainerScrollView : public BScrollView {
|
||||||
|
public:
|
||||||
|
DownloadContainerScrollView(BView* target)
|
||||||
|
:
|
||||||
|
BScrollView("Downloads scroll view", target, 0, false, true,
|
||||||
|
B_NO_BORDER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DoLayout()
|
||||||
|
{
|
||||||
|
BScrollView::DoLayout();
|
||||||
|
// Tweak scroll bar layout to hide part of the frame for better looks.
|
||||||
|
BScrollBar* scrollBar = ScrollBar(B_VERTICAL);
|
||||||
|
scrollBar->MoveBy(1, -1);
|
||||||
|
scrollBar->ResizeBy(0, 2);
|
||||||
|
Target()->ResizeBy(1, 0);
|
||||||
|
// Set the scroll steps
|
||||||
|
if (BView* item = Target()->ChildAt(0)) {
|
||||||
|
scrollBar->SetSteps(item->MinSize().height + 1,
|
||||||
|
item->MinSize().height + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
DownloadWindow::DownloadWindow(BRect frame, bool visible,
|
||||||
|
SettingsMessage* settings)
|
||||||
|
: BWindow(frame, "Downloads",
|
||||||
|
B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
|
||||||
|
B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE),
|
||||||
|
fMinimizeOnClose(false)
|
||||||
|
{
|
||||||
|
SetPulseRate(1000000);
|
||||||
|
|
||||||
|
settings->AddListener(BMessenger(this));
|
||||||
|
BPath downloadPath;
|
||||||
|
if (find_directory(B_DESKTOP_DIRECTORY, &downloadPath) != B_OK)
|
||||||
|
downloadPath.SetTo("/boot/home/Desktop");
|
||||||
|
fDownloadPath = settings->GetValue(kSettingsKeyDownloadPath,
|
||||||
|
downloadPath.Path());
|
||||||
|
settings->SetValue(kSettingsKeyDownloadPath, fDownloadPath);
|
||||||
|
|
||||||
|
SetLayout(new BGroupLayout(B_VERTICAL, 0.0));
|
||||||
|
|
||||||
|
DownloadsContainerView* downloadsGroupView = new DownloadsContainerView();
|
||||||
|
fDownloadViewsLayout = downloadsGroupView->GroupLayout();
|
||||||
|
|
||||||
|
BMenuBar* menuBar = new BMenuBar("Menu bar");
|
||||||
|
BMenu* menu = new BMenu("Downloads");
|
||||||
|
menu->AddItem(new BMenuItem("Open downloads folder",
|
||||||
|
new BMessage(OPEN_DOWNLOADS_FOLDER)));
|
||||||
|
BMessage* newWindowMessage = new BMessage(NEW_WINDOW);
|
||||||
|
newWindowMessage->AddString("url", "");
|
||||||
|
BMenuItem* newWindowItem = new BMenuItem("New browser window",
|
||||||
|
newWindowMessage, 'N');
|
||||||
|
menu->AddItem(newWindowItem);
|
||||||
|
newWindowItem->SetTarget(be_app);
|
||||||
|
menu->AddSeparatorItem();
|
||||||
|
menu->AddItem(new BMenuItem("Hide", new BMessage(B_QUIT_REQUESTED), 'D'));
|
||||||
|
menuBar->AddItem(menu);
|
||||||
|
|
||||||
|
fDownloadsScrollView = new DownloadContainerScrollView(downloadsGroupView);
|
||||||
|
|
||||||
|
fRemoveFinishedButton = new BButton("Remove finished",
|
||||||
|
new BMessage(REMOVE_FINISHED_DOWNLOADS));
|
||||||
|
fRemoveFinishedButton->SetEnabled(false);
|
||||||
|
|
||||||
|
fRemoveMissingButton = new BButton("Remove missing",
|
||||||
|
new BMessage(REMOVE_MISSING_DOWNLOADS));
|
||||||
|
fRemoveMissingButton->SetEnabled(false);
|
||||||
|
|
||||||
|
const float spacing = be_control_look->DefaultItemSpacing();
|
||||||
|
|
||||||
|
AddChild(BGroupLayoutBuilder(B_VERTICAL, 0.0)
|
||||||
|
.Add(menuBar)
|
||||||
|
.Add(fDownloadsScrollView)
|
||||||
|
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
|
||||||
|
.Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing)
|
||||||
|
.AddGlue()
|
||||||
|
.Add(fRemoveMissingButton)
|
||||||
|
.Add(fRemoveFinishedButton)
|
||||||
|
.SetInsets(12, 5, 12, 5)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
PostMessage(INIT);
|
||||||
|
|
||||||
|
if (!visible)
|
||||||
|
Hide();
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DownloadWindow::~DownloadWindow()
|
||||||
|
{
|
||||||
|
// Only necessary to save the current progress of unfinished downloads:
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::DispatchMessage(BMessage* message, BHandler* target)
|
||||||
|
{
|
||||||
|
// We need to intercept mouse down events inside the area of download
|
||||||
|
// progress views (regardless of whether they have children at the click),
|
||||||
|
// so that they may display a context menu.
|
||||||
|
BPoint where;
|
||||||
|
int32 buttons;
|
||||||
|
if (message->what == B_MOUSE_DOWN
|
||||||
|
&& message->FindPoint("screen_where", &where) == B_OK
|
||||||
|
&& message->FindInt32("buttons", &buttons) == B_OK
|
||||||
|
&& (buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
BPoint viewWhere(where);
|
||||||
|
view->ConvertFromScreen(&viewWhere);
|
||||||
|
if (view->Bounds().Contains(viewWhere)) {
|
||||||
|
view->ShowContextMenu(where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BWindow::DispatchMessage(message, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case INIT:
|
||||||
|
{
|
||||||
|
_LoadSettings();
|
||||||
|
// Small trick to get the correct enabled status of the Remove
|
||||||
|
// finished button
|
||||||
|
_DownloadFinished(NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B_DOWNLOAD_ADDED:
|
||||||
|
{
|
||||||
|
BWebDownload* download;
|
||||||
|
if (message->FindPointer("download", reinterpret_cast<void**>(
|
||||||
|
&download)) == B_OK) {
|
||||||
|
_DownloadStarted(download);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case B_DOWNLOAD_REMOVED:
|
||||||
|
{
|
||||||
|
BWebDownload* download;
|
||||||
|
if (message->FindPointer("download", reinterpret_cast<void**>(
|
||||||
|
&download)) == B_OK) {
|
||||||
|
_DownloadFinished(download);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPEN_DOWNLOADS_FOLDER:
|
||||||
|
{
|
||||||
|
entry_ref ref;
|
||||||
|
status_t status = get_ref_for_path(fDownloadPath.String(), &ref);
|
||||||
|
if (status == B_OK)
|
||||||
|
status = be_roster->Launch(&ref);
|
||||||
|
if (status != B_OK && status != B_ALREADY_RUNNING) {
|
||||||
|
BString errorString("The downloads folder could not be "
|
||||||
|
"opened.\n\n");
|
||||||
|
errorString << "Error: " << strerror(status);
|
||||||
|
BAlert* alert = new BAlert("Error opening downloads folder",
|
||||||
|
errorString.String(), "OK");
|
||||||
|
alert->Go(NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REMOVE_FINISHED_DOWNLOADS:
|
||||||
|
_RemoveFinishedDownloads();
|
||||||
|
break;
|
||||||
|
case REMOVE_MISSING_DOWNLOADS:
|
||||||
|
_RemoveMissingDownloads();
|
||||||
|
break;
|
||||||
|
case SAVE_SETTINGS:
|
||||||
|
_ValidateButtonStatus();
|
||||||
|
_SaveSettings();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SETTINGS_VALUE_CHANGED:
|
||||||
|
{
|
||||||
|
BString string;
|
||||||
|
if (message->FindString("name", &string) == B_OK
|
||||||
|
&& string == kSettingsKeyDownloadPath
|
||||||
|
&& message->FindString("value", &string) == B_OK) {
|
||||||
|
fDownloadPath = string;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BWindow::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadWindow::QuitRequested()
|
||||||
|
{
|
||||||
|
if (fMinimizeOnClose) {
|
||||||
|
if (!IsMinimized())
|
||||||
|
Minimize(true);
|
||||||
|
} else {
|
||||||
|
if (!IsHidden())
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadWindow::DownloadsInProgress()
|
||||||
|
{
|
||||||
|
bool downloadsInProgress = false;
|
||||||
|
if (!Lock())
|
||||||
|
return downloadsInProgress;
|
||||||
|
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
if (view->Download() != NULL) {
|
||||||
|
downloadsInProgress = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Unlock();
|
||||||
|
|
||||||
|
return downloadsInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::SetMinimizeOnClose(bool minimize)
|
||||||
|
{
|
||||||
|
if (Lock()) {
|
||||||
|
fMinimizeOnClose = minimize;
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_DownloadStarted(BWebDownload* download)
|
||||||
|
{
|
||||||
|
download->Start(BPath(fDownloadPath.String()));
|
||||||
|
|
||||||
|
int32 finishedCount = 0;
|
||||||
|
int32 missingCount = 0;
|
||||||
|
int32 index = 0;
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
if (view->URL() == download->URL()) {
|
||||||
|
index = i;
|
||||||
|
view->RemoveSelf();
|
||||||
|
delete view;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (view->IsFinished())
|
||||||
|
finishedCount++;
|
||||||
|
if (view->IsMissing())
|
||||||
|
missingCount++;
|
||||||
|
}
|
||||||
|
fRemoveFinishedButton->SetEnabled(finishedCount > 0);
|
||||||
|
fRemoveMissingButton->SetEnabled(missingCount > 0);
|
||||||
|
DownloadProgressView* view = new DownloadProgressView(download);
|
||||||
|
if (!view->Init()) {
|
||||||
|
delete view;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fDownloadViewsLayout->AddView(index, view);
|
||||||
|
|
||||||
|
// Scroll new download into view
|
||||||
|
if (BScrollBar* scrollBar = fDownloadsScrollView->ScrollBar(B_VERTICAL)) {
|
||||||
|
float min;
|
||||||
|
float max;
|
||||||
|
scrollBar->GetRange(&min, &max);
|
||||||
|
float viewHeight = view->MinSize().height + 1;
|
||||||
|
float scrollOffset = min + index * viewHeight;
|
||||||
|
float scrollBarHeight = scrollBar->Bounds().Height() - 1;
|
||||||
|
float value = scrollBar->Value();
|
||||||
|
if (scrollOffset < value)
|
||||||
|
scrollBar->SetValue(scrollOffset);
|
||||||
|
else if (scrollOffset + viewHeight > value + scrollBarHeight) {
|
||||||
|
float diff = scrollOffset + viewHeight - (value + scrollBarHeight);
|
||||||
|
scrollBar->SetValue(value + diff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_SaveSettings();
|
||||||
|
|
||||||
|
SetWorkspaces(B_CURRENT_WORKSPACE);
|
||||||
|
if (IsHidden())
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_DownloadFinished(BWebDownload* download)
|
||||||
|
{
|
||||||
|
int32 finishedCount = 0;
|
||||||
|
int32 missingCount = 0;
|
||||||
|
for (int32 i = 0;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i++) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
if (download && view->Download() == download) {
|
||||||
|
view->DownloadFinished();
|
||||||
|
finishedCount++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (view->IsFinished())
|
||||||
|
finishedCount++;
|
||||||
|
if (view->IsMissing())
|
||||||
|
missingCount++;
|
||||||
|
}
|
||||||
|
fRemoveFinishedButton->SetEnabled(finishedCount > 0);
|
||||||
|
fRemoveMissingButton->SetEnabled(missingCount > 0);
|
||||||
|
if (download)
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_RemoveFinishedDownloads()
|
||||||
|
{
|
||||||
|
int32 missingCount = 0;
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
if (view->IsFinished()) {
|
||||||
|
view->RemoveSelf();
|
||||||
|
delete view;
|
||||||
|
} else if (view->IsMissing())
|
||||||
|
missingCount++;
|
||||||
|
}
|
||||||
|
fRemoveFinishedButton->SetEnabled(false);
|
||||||
|
fRemoveMissingButton->SetEnabled(missingCount > 0);
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_RemoveMissingDownloads()
|
||||||
|
{
|
||||||
|
int32 finishedCount = 0;
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
if (view->IsMissing()) {
|
||||||
|
view->RemoveSelf();
|
||||||
|
delete view;
|
||||||
|
} else if (view->IsFinished())
|
||||||
|
finishedCount++;
|
||||||
|
}
|
||||||
|
fRemoveMissingButton->SetEnabled(false);
|
||||||
|
fRemoveFinishedButton->SetEnabled(finishedCount > 0);
|
||||||
|
_SaveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_ValidateButtonStatus()
|
||||||
|
{
|
||||||
|
int32 finishedCount = 0;
|
||||||
|
int32 missingCount = 0;
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
if (view->IsFinished())
|
||||||
|
finishedCount++;
|
||||||
|
if (view->IsMissing())
|
||||||
|
missingCount++;
|
||||||
|
}
|
||||||
|
fRemoveFinishedButton->SetEnabled(finishedCount > 0);
|
||||||
|
fRemoveMissingButton->SetEnabled(missingCount > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_SaveSettings()
|
||||||
|
{
|
||||||
|
BFile file;
|
||||||
|
if (!_OpenSettingsFile(file, B_ERASE_FILE | B_CREATE_FILE | B_WRITE_ONLY))
|
||||||
|
return;
|
||||||
|
BMessage message;
|
||||||
|
for (int32 i = fDownloadViewsLayout->CountItems() - 1;
|
||||||
|
BLayoutItem* item = fDownloadViewsLayout->ItemAt(i); i--) {
|
||||||
|
DownloadProgressView* view = dynamic_cast<DownloadProgressView*>(
|
||||||
|
item->View());
|
||||||
|
if (!view)
|
||||||
|
continue;
|
||||||
|
BMessage downloadArchive;
|
||||||
|
if (view->SaveSettings(&downloadArchive) == B_OK)
|
||||||
|
message.AddMessage("download", &downloadArchive);
|
||||||
|
}
|
||||||
|
message.Flatten(&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DownloadWindow::_LoadSettings()
|
||||||
|
{
|
||||||
|
BFile file;
|
||||||
|
if (!_OpenSettingsFile(file, B_READ_ONLY))
|
||||||
|
return;
|
||||||
|
BMessage message;
|
||||||
|
if (message.Unflatten(&file) != B_OK)
|
||||||
|
return;
|
||||||
|
BMessage downloadArchive;
|
||||||
|
for (int32 i = 0;
|
||||||
|
message.FindMessage("download", i, &downloadArchive) == B_OK;
|
||||||
|
i++) {
|
||||||
|
DownloadProgressView* view = new DownloadProgressView(
|
||||||
|
&downloadArchive);
|
||||||
|
if (!view->Init(&downloadArchive))
|
||||||
|
continue;
|
||||||
|
fDownloadViewsLayout->AddView(0, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DownloadWindow::_OpenSettingsFile(BFile& file, uint32 mode)
|
||||||
|
{
|
||||||
|
BPath path;
|
||||||
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK
|
||||||
|
|| path.Append(kApplicationName) != B_OK
|
||||||
|
|| path.Append("Downloads") != B_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return file.SetTo(path.Path(), mode) == B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef DOWNLOAD_WINDOW_H
|
||||||
|
#define DOWNLOAD_WINDOW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
class BButton;
|
||||||
|
class BFile;
|
||||||
|
class BGroupLayout;
|
||||||
|
class BScrollView;
|
||||||
|
class BWebDownload;
|
||||||
|
class SettingsMessage;
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadWindow : public BWindow {
|
||||||
|
public:
|
||||||
|
DownloadWindow(BRect frame, bool visible,
|
||||||
|
SettingsMessage* settings);
|
||||||
|
virtual ~DownloadWindow();
|
||||||
|
|
||||||
|
virtual void DispatchMessage(BMessage* message,
|
||||||
|
BHandler* target);
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
|
bool DownloadsInProgress();
|
||||||
|
void SetMinimizeOnClose(bool minimize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _DownloadStarted(BWebDownload* download);
|
||||||
|
void _DownloadFinished(BWebDownload* download);
|
||||||
|
void _RemoveFinishedDownloads();
|
||||||
|
void _RemoveMissingDownloads();
|
||||||
|
void _ValidateButtonStatus();
|
||||||
|
void _SaveSettings();
|
||||||
|
void _LoadSettings();
|
||||||
|
bool _OpenSettingsFile(BFile& file, uint32 mode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BScrollView* fDownloadsScrollView;
|
||||||
|
BGroupLayout* fDownloadViewsLayout;
|
||||||
|
BButton* fRemoveFinishedButton;
|
||||||
|
BButton* fRemoveMissingButton;
|
||||||
|
BString fDownloadPath;
|
||||||
|
bool fMinimizeOnClose;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DOWNLOAD_WINDOW_H
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
SubDir HAIKU_TOP src apps webpositive ;
|
||||||
|
|
||||||
|
SubDirSysHdrs $(HAIKU_WEBKIT_HEADERS) ;
|
||||||
|
|
||||||
|
SubDirC++Flags $(defines) -Wno-error=sequence-point ;
|
||||||
|
SubDirCcFlags $(defines) -Wno-error=sequence-point ;
|
||||||
|
|
||||||
|
# source directories
|
||||||
|
local sourceDirs =
|
||||||
|
autocompletion
|
||||||
|
support
|
||||||
|
tabview
|
||||||
|
;
|
||||||
|
|
||||||
|
local sourceDir ;
|
||||||
|
for sourceDir in $(sourceDirs) {
|
||||||
|
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src apps webpositive $(sourceDir) ] ;
|
||||||
|
}
|
||||||
|
|
||||||
|
local sources =
|
||||||
|
# autocompletion
|
||||||
|
AutoCompleter.cpp
|
||||||
|
AutoCompleterDefaultImpl.cpp
|
||||||
|
TextViewCompleter.cpp
|
||||||
|
|
||||||
|
# support
|
||||||
|
BaseURL.cpp
|
||||||
|
BitmapButton.cpp
|
||||||
|
DateTime.cpp
|
||||||
|
FontSelectionView.cpp
|
||||||
|
IconButton.cpp
|
||||||
|
SettingsMessage.cpp
|
||||||
|
StringForSize.cpp
|
||||||
|
|
||||||
|
# tabview
|
||||||
|
TabContainerView.cpp
|
||||||
|
TabManager.cpp
|
||||||
|
TabView.cpp
|
||||||
|
|
||||||
|
AuthenticationPanel.cpp
|
||||||
|
BrowserApp.cpp
|
||||||
|
BrowserWindow.cpp
|
||||||
|
BrowsingHistory.cpp
|
||||||
|
CredentialsStorage.cpp
|
||||||
|
DownloadProgressView.cpp
|
||||||
|
DownloadWindow.cpp
|
||||||
|
SettingsKeys.cpp
|
||||||
|
SettingsWindow.cpp
|
||||||
|
svn_revision.cpp
|
||||||
|
URLInputGroup.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
Includes [ FGristFiles $(sources) ] : $(HAIKU_WEBKIT_HEADERS_DEPENDENCY) ;
|
||||||
|
# Dependency needed to trigger downloading/unzipping the package before
|
||||||
|
# compiling the files.
|
||||||
|
|
||||||
|
# SVN revision
|
||||||
|
#local svnRevisionFile = [ FGristFiles svn_revision ] ;
|
||||||
|
#MakeLocate $(svnRevisionFile) : $(LOCATE_TARGET) ;
|
||||||
|
#CreateSVNRevisionFile $(svnRevisionFile) ;
|
||||||
|
|
||||||
|
Application WebPositive :
|
||||||
|
$(sources)
|
||||||
|
:
|
||||||
|
$(HAIKU_WEBKIT_LIBS)
|
||||||
|
$(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS)
|
||||||
|
be network tracker translation
|
||||||
|
:
|
||||||
|
WebPositive.rdef
|
||||||
|
;
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SettingsKeys.h"
|
||||||
|
|
||||||
|
const char* kSettingsKeyDownloadPath = "download path";
|
||||||
|
const char* kSettingsKeyShowTabsIfSinglePageOpen
|
||||||
|
= "show tabs if single page open";
|
||||||
|
const char* kSettingsKeyAutoHideInterfaceInFullscreenMode
|
||||||
|
= "auto hide interface in full screen mode";
|
||||||
|
const char* kSettingsKeyAutoHidePointer = "auto hide pointer";
|
||||||
|
const char* kSettingsKeyShowHomeButton = "show home button";
|
||||||
|
|
||||||
|
const char* kSettingsKeyNewWindowPolicy = "new window policy";
|
||||||
|
const char* kSettingsKeyNewTabPolicy = "new tab policy";
|
||||||
|
const char* kSettingsKeyStartPageURL = "start page url";
|
||||||
|
const char* kSettingsKeySearchPageURL = "search page url";
|
||||||
|
|
||||||
|
|
||||||
|
const char* kDefaultDownloadPath = "/boot/home/Desktop/";
|
||||||
|
const char* kDefaultStartPageURL
|
||||||
|
= "file:///boot/home/config/settings/WebPositive/LoaderPages/Welcome";
|
||||||
|
const char* kDefaultSearchPageURL = "http://www.google.com";
|
||||||
|
|
||||||
|
const char* kSettingsKeyUseProxy = "use http proxy";
|
||||||
|
const char* kSettingsKeyProxyAddress = "http proxy address";
|
||||||
|
const char* kSettingsKeyProxyPort = "http proxy port";
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef SETTINGS_KEYS_H
|
||||||
|
#define SETTINGS_KEYS_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern const char* kSettingsKeyDownloadPath;
|
||||||
|
extern const char* kSettingsKeyShowTabsIfSinglePageOpen;
|
||||||
|
extern const char* kSettingsKeyAutoHideInterfaceInFullscreenMode;
|
||||||
|
extern const char* kSettingsKeyAutoHidePointer;
|
||||||
|
extern const char* kSettingsKeyShowHomeButton;
|
||||||
|
|
||||||
|
extern const char* kSettingsKeyNewWindowPolicy;
|
||||||
|
extern const char* kSettingsKeyNewTabPolicy;
|
||||||
|
extern const char* kSettingsKeyStartPageURL;
|
||||||
|
extern const char* kSettingsKeySearchPageURL;
|
||||||
|
|
||||||
|
extern const char* kDefaultDownloadPath;
|
||||||
|
extern const char* kDefaultStartPageURL;
|
||||||
|
extern const char* kDefaultSearchPageURL;
|
||||||
|
|
||||||
|
extern const char* kSettingsKeyUseProxy;
|
||||||
|
extern const char* kSettingsKeyProxyAddress;
|
||||||
|
extern const char* kSettingsKeyProxyPort;
|
||||||
|
|
||||||
|
#endif // SETTINGS_KEYS_H
|
||||||
@@ -0,0 +1,885 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "SettingsWindow.h"
|
||||||
|
|
||||||
|
#include <Button.h>
|
||||||
|
#include <CheckBox.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <GridLayoutBuilder.h>
|
||||||
|
#include <GroupLayout.h>
|
||||||
|
#include <GroupLayoutBuilder.h>
|
||||||
|
#include <Locale.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <MenuField.h>
|
||||||
|
#include <Message.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <ScrollView.h>
|
||||||
|
#include <SeparatorView.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
#include <TabView.h>
|
||||||
|
#include <TextControl.h>
|
||||||
|
#include <debugger.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "BrowserApp.h"
|
||||||
|
#include "BrowsingHistory.h"
|
||||||
|
#include "BrowserWindow.h"
|
||||||
|
#include "FontSelectionView.h"
|
||||||
|
#include "SettingsKeys.h"
|
||||||
|
#include "SettingsMessage.h"
|
||||||
|
#include "WebSettings.h"
|
||||||
|
|
||||||
|
|
||||||
|
#undef B_TRANSLATION_CONTEXT
|
||||||
|
#define B_TRANSLATION_CONTEXT "Settings Window"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_APPLY = 'aply',
|
||||||
|
MSG_CANCEL = 'cncl',
|
||||||
|
MSG_REVERT = 'rvrt',
|
||||||
|
|
||||||
|
MSG_START_PAGE_CHANGED = 'hpch',
|
||||||
|
MSG_SEARCH_PAGE_CHANGED = 'spch',
|
||||||
|
MSG_DOWNLOAD_FOLDER_CHANGED = 'dnfc',
|
||||||
|
MSG_NEW_WINDOWS_BEHAVIOR_CHANGED = 'nwbc',
|
||||||
|
MSG_NEW_TABS_BEHAVIOR_CHANGED = 'ntbc',
|
||||||
|
MSG_HISTORY_MENU_DAYS_CHANGED = 'digm',
|
||||||
|
MSG_TAB_DISPLAY_BEHAVIOR_CHANGED = 'tdbc',
|
||||||
|
MSG_AUTO_HIDE_INTERFACE_BEHAVIOR_CHANGED = 'ahic',
|
||||||
|
MSG_AUTO_HIDE_POINTER_BEHAVIOR_CHANGED = 'ahpc',
|
||||||
|
MSG_SHOW_HOME_BUTTON_CHANGED = 'shbc',
|
||||||
|
|
||||||
|
MSG_STANDARD_FONT_CHANGED = 'stfc',
|
||||||
|
MSG_SERIF_FONT_CHANGED = 'sefc',
|
||||||
|
MSG_SANS_SERIF_FONT_CHANGED = 'ssfc',
|
||||||
|
MSG_FIXED_FONT_CHANGED = 'ffch',
|
||||||
|
|
||||||
|
MSG_STANDARD_FONT_SIZE_SELECTED = 'sfss',
|
||||||
|
MSG_FIXED_FONT_SIZE_SELECTED = 'ffss',
|
||||||
|
|
||||||
|
MSG_USE_PROXY_CHANGED = 'upsc',
|
||||||
|
MSG_PROXY_ADDRESS_CHANGED = 'psac',
|
||||||
|
MSG_PROXY_PORT_CHANGED = 'pspc',
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int32 kDefaultFontSize = 14;
|
||||||
|
|
||||||
|
|
||||||
|
SettingsWindow::SettingsWindow(BRect frame, SettingsMessage* settings)
|
||||||
|
:
|
||||||
|
BWindow(frame, B_TRANSLATE("Settings"), B_TITLED_WINDOW_LOOK,
|
||||||
|
B_NORMAL_WINDOW_FEEL, B_AUTO_UPDATE_SIZE_LIMITS
|
||||||
|
| B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE),
|
||||||
|
fSettings(settings)
|
||||||
|
{
|
||||||
|
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||||
|
|
||||||
|
fApplyButton = new BButton(B_TRANSLATE("Apply"), new BMessage(MSG_APPLY));
|
||||||
|
fCancelButton = new BButton(B_TRANSLATE("Cancel"),
|
||||||
|
new BMessage(MSG_CANCEL));
|
||||||
|
fRevertButton = new BButton(B_TRANSLATE("Revert"),
|
||||||
|
new BMessage(MSG_REVERT));
|
||||||
|
|
||||||
|
float spacing = be_control_look->DefaultItemSpacing();
|
||||||
|
|
||||||
|
BTabView* tabView = new BTabView("settings pages", B_WIDTH_FROM_LABEL);
|
||||||
|
|
||||||
|
AddChild(BGroupLayoutBuilder(B_VERTICAL, spacing)
|
||||||
|
.Add(tabView)
|
||||||
|
.Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing)
|
||||||
|
.Add(fRevertButton)
|
||||||
|
.AddGlue()
|
||||||
|
.Add(fCancelButton)
|
||||||
|
.Add(fApplyButton)
|
||||||
|
)
|
||||||
|
.SetInsets(spacing, spacing, spacing, spacing)
|
||||||
|
);
|
||||||
|
|
||||||
|
tabView->AddTab(_CreateGeneralPage(spacing));
|
||||||
|
tabView->AddTab(_CreateFontsPage(spacing));
|
||||||
|
tabView->AddTab(_CreateProxyPage(spacing));
|
||||||
|
|
||||||
|
_SetupFontSelectionView(fStandardFontView,
|
||||||
|
new BMessage(MSG_STANDARD_FONT_CHANGED));
|
||||||
|
_SetupFontSelectionView(fSerifFontView,
|
||||||
|
new BMessage(MSG_SERIF_FONT_CHANGED));
|
||||||
|
_SetupFontSelectionView(fSansSerifFontView,
|
||||||
|
new BMessage(MSG_SANS_SERIF_FONT_CHANGED));
|
||||||
|
_SetupFontSelectionView(fFixedFontView,
|
||||||
|
new BMessage(MSG_FIXED_FONT_CHANGED));
|
||||||
|
|
||||||
|
fApplyButton->MakeDefault(true);
|
||||||
|
|
||||||
|
if (!frame.IsValid())
|
||||||
|
CenterOnScreen();
|
||||||
|
|
||||||
|
// load settings from disk
|
||||||
|
_RevertSettings();
|
||||||
|
// apply to WebKit
|
||||||
|
_ApplySettings();
|
||||||
|
|
||||||
|
// Start hidden
|
||||||
|
Hide();
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsWindow::~SettingsWindow()
|
||||||
|
{
|
||||||
|
RemoveHandler(fStandardFontView);
|
||||||
|
delete fStandardFontView;
|
||||||
|
RemoveHandler(fSerifFontView);
|
||||||
|
delete fSerifFontView;
|
||||||
|
RemoveHandler(fSansSerifFontView);
|
||||||
|
delete fSansSerifFontView;
|
||||||
|
RemoveHandler(fFixedFontView);
|
||||||
|
delete fFixedFontView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case MSG_APPLY:
|
||||||
|
_ApplySettings();
|
||||||
|
break;
|
||||||
|
case MSG_CANCEL:
|
||||||
|
_RevertSettings();
|
||||||
|
PostMessage(B_QUIT_REQUESTED);
|
||||||
|
break;
|
||||||
|
case MSG_REVERT:
|
||||||
|
_RevertSettings();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MSG_STANDARD_FONT_SIZE_SELECTED:
|
||||||
|
{
|
||||||
|
int32 size = _SizesMenuValue(fStandardSizesMenu->Menu());
|
||||||
|
fStandardFontView->SetSize(size);
|
||||||
|
fSerifFontView->SetSize(size);
|
||||||
|
fSansSerifFontView->SetSize(size);
|
||||||
|
_ValidateControlsEnabledStatus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_FIXED_FONT_SIZE_SELECTED:
|
||||||
|
{
|
||||||
|
int32 size = _SizesMenuValue(fFixedSizesMenu->Menu());
|
||||||
|
fFixedFontView->SetSize(size);
|
||||||
|
_ValidateControlsEnabledStatus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MSG_START_PAGE_CHANGED:
|
||||||
|
case MSG_SEARCH_PAGE_CHANGED:
|
||||||
|
case MSG_DOWNLOAD_FOLDER_CHANGED:
|
||||||
|
case MSG_NEW_WINDOWS_BEHAVIOR_CHANGED:
|
||||||
|
case MSG_NEW_TABS_BEHAVIOR_CHANGED:
|
||||||
|
case MSG_HISTORY_MENU_DAYS_CHANGED:
|
||||||
|
case MSG_TAB_DISPLAY_BEHAVIOR_CHANGED:
|
||||||
|
case MSG_AUTO_HIDE_INTERFACE_BEHAVIOR_CHANGED:
|
||||||
|
case MSG_AUTO_HIDE_POINTER_BEHAVIOR_CHANGED:
|
||||||
|
case MSG_SHOW_HOME_BUTTON_CHANGED:
|
||||||
|
case MSG_STANDARD_FONT_CHANGED:
|
||||||
|
case MSG_SERIF_FONT_CHANGED:
|
||||||
|
case MSG_SANS_SERIF_FONT_CHANGED:
|
||||||
|
case MSG_FIXED_FONT_CHANGED:
|
||||||
|
case MSG_USE_PROXY_CHANGED:
|
||||||
|
case MSG_PROXY_ADDRESS_CHANGED:
|
||||||
|
case MSG_PROXY_PORT_CHANGED:
|
||||||
|
// TODO: Some settings could change live, some others not?
|
||||||
|
_ValidateControlsEnabledStatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BWindow::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsWindow::QuitRequested()
|
||||||
|
{
|
||||||
|
if (!IsHidden())
|
||||||
|
Hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::Show()
|
||||||
|
{
|
||||||
|
// When showing the window, the this is always the
|
||||||
|
// point to which we can revert the settings.
|
||||||
|
_RevertSettings();
|
||||||
|
BWindow::Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
SettingsWindow::_CreateGeneralPage(float spacing)
|
||||||
|
{
|
||||||
|
fStartPageControl = new BTextControl("start page",
|
||||||
|
B_TRANSLATE("Start page:"), "", new BMessage(MSG_START_PAGE_CHANGED));
|
||||||
|
fStartPageControl->SetModificationMessage(
|
||||||
|
new BMessage(MSG_START_PAGE_CHANGED));
|
||||||
|
fStartPageControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeyStartPageURL, kDefaultStartPageURL));
|
||||||
|
|
||||||
|
fSearchPageControl = new BTextControl("search page",
|
||||||
|
B_TRANSLATE("Search page:"), "",
|
||||||
|
new BMessage(MSG_SEARCH_PAGE_CHANGED));
|
||||||
|
fSearchPageControl->SetModificationMessage(
|
||||||
|
new BMessage(MSG_SEARCH_PAGE_CHANGED));
|
||||||
|
fSearchPageControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeySearchPageURL, kDefaultSearchPageURL));
|
||||||
|
|
||||||
|
fDownloadFolderControl = new BTextControl("download folder",
|
||||||
|
B_TRANSLATE("Download folder:"), "",
|
||||||
|
new BMessage(MSG_DOWNLOAD_FOLDER_CHANGED));
|
||||||
|
fDownloadFolderControl->SetModificationMessage(
|
||||||
|
new BMessage(MSG_DOWNLOAD_FOLDER_CHANGED));
|
||||||
|
fDownloadFolderControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeyDownloadPath, kDefaultDownloadPath));
|
||||||
|
|
||||||
|
fNewWindowBehaviorOpenHomeItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Open start page"),
|
||||||
|
new BMessage(MSG_NEW_WINDOWS_BEHAVIOR_CHANGED));
|
||||||
|
fNewWindowBehaviorOpenSearchItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Open search page"),
|
||||||
|
new BMessage(MSG_NEW_WINDOWS_BEHAVIOR_CHANGED));
|
||||||
|
fNewWindowBehaviorOpenBlankItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Open blank page"),
|
||||||
|
new BMessage(MSG_NEW_WINDOWS_BEHAVIOR_CHANGED));
|
||||||
|
|
||||||
|
fNewTabBehaviorCloneCurrentItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Clone current page"),
|
||||||
|
new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
|
||||||
|
fNewTabBehaviorOpenHomeItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Open start page"),
|
||||||
|
new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
|
||||||
|
fNewTabBehaviorOpenSearchItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Open search page"),
|
||||||
|
new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
|
||||||
|
fNewTabBehaviorOpenBlankItem = new BMenuItem(
|
||||||
|
B_TRANSLATE("Open blank page"),
|
||||||
|
new BMessage(MSG_NEW_TABS_BEHAVIOR_CHANGED));
|
||||||
|
|
||||||
|
fNewWindowBehaviorOpenHomeItem->SetMarked(true);
|
||||||
|
fNewTabBehaviorOpenBlankItem->SetMarked(true);
|
||||||
|
|
||||||
|
BPopUpMenu* newWindowBehaviorMenu = new BPopUpMenu("New windows");
|
||||||
|
newWindowBehaviorMenu->AddItem(fNewWindowBehaviorOpenHomeItem);
|
||||||
|
newWindowBehaviorMenu->AddItem(fNewWindowBehaviorOpenSearchItem);
|
||||||
|
newWindowBehaviorMenu->AddItem(fNewWindowBehaviorOpenBlankItem);
|
||||||
|
fNewWindowBehaviorMenu = new BMenuField("new window behavior",
|
||||||
|
B_TRANSLATE("New windows:"), newWindowBehaviorMenu);
|
||||||
|
|
||||||
|
BPopUpMenu* newTabBehaviorMenu = new BPopUpMenu("New tabs");
|
||||||
|
newTabBehaviorMenu->AddItem(fNewTabBehaviorOpenBlankItem);
|
||||||
|
newTabBehaviorMenu->AddItem(fNewTabBehaviorOpenHomeItem);
|
||||||
|
newTabBehaviorMenu->AddItem(fNewTabBehaviorOpenSearchItem);
|
||||||
|
newTabBehaviorMenu->AddItem(fNewTabBehaviorCloneCurrentItem);
|
||||||
|
fNewTabBehaviorMenu = new BMenuField("new tab behavior",
|
||||||
|
B_TRANSLATE("New tabs:"), newTabBehaviorMenu);
|
||||||
|
|
||||||
|
fDaysInHistoryMenuControl = new BTextControl("days in history",
|
||||||
|
B_TRANSLATE("Number of days to keep links in History menu:"), "",
|
||||||
|
new BMessage(MSG_HISTORY_MENU_DAYS_CHANGED));
|
||||||
|
fDaysInHistoryMenuControl->SetModificationMessage(
|
||||||
|
new BMessage(MSG_HISTORY_MENU_DAYS_CHANGED));
|
||||||
|
BString maxHistoryAge;
|
||||||
|
maxHistoryAge << BrowsingHistory::DefaultInstance()->MaxHistoryItemAge();
|
||||||
|
fDaysInHistoryMenuControl->SetText(maxHistoryAge.String());
|
||||||
|
for (uchar i = 0; i < '0'; i++)
|
||||||
|
fDaysInHistoryMenuControl->TextView()->DisallowChar(i);
|
||||||
|
for (uchar i = '9' + 1; i <= 128; i++)
|
||||||
|
fDaysInHistoryMenuControl->TextView()->DisallowChar(i);
|
||||||
|
|
||||||
|
fShowTabsIfOnlyOnePage = new BCheckBox("show tabs if only one page",
|
||||||
|
B_TRANSLATE("Show tabs if only one page is open."),
|
||||||
|
new BMessage(MSG_TAB_DISPLAY_BEHAVIOR_CHANGED));
|
||||||
|
fShowTabsIfOnlyOnePage->SetValue(B_CONTROL_ON);
|
||||||
|
|
||||||
|
fAutoHideInterfaceInFullscreenMode = new BCheckBox("auto-hide interface",
|
||||||
|
B_TRANSLATE("Auto-hide interface in fullscreen mode."),
|
||||||
|
new BMessage(MSG_AUTO_HIDE_INTERFACE_BEHAVIOR_CHANGED));
|
||||||
|
fAutoHideInterfaceInFullscreenMode->SetValue(B_CONTROL_OFF);
|
||||||
|
|
||||||
|
fAutoHidePointer = new BCheckBox("auto-hide pointer",
|
||||||
|
B_TRANSLATE("Auto-hide mouse pointer."),
|
||||||
|
new BMessage(MSG_AUTO_HIDE_POINTER_BEHAVIOR_CHANGED));
|
||||||
|
fAutoHidePointer->SetValue(B_CONTROL_OFF);
|
||||||
|
|
||||||
|
fShowHomeButton = new BCheckBox("show home button",
|
||||||
|
B_TRANSLATE("Show Home Button"),
|
||||||
|
new BMessage(MSG_SHOW_HOME_BUTTON_CHANGED));
|
||||||
|
fShowHomeButton->SetValue(B_CONTROL_ON);
|
||||||
|
|
||||||
|
BView* view = BGroupLayoutBuilder(B_VERTICAL, spacing / 2)
|
||||||
|
.Add(BGridLayoutBuilder(spacing / 2, spacing / 2)
|
||||||
|
.Add(fStartPageControl->CreateLabelLayoutItem(), 0, 0)
|
||||||
|
.Add(fStartPageControl->CreateTextViewLayoutItem(), 1, 0)
|
||||||
|
|
||||||
|
.Add(fSearchPageControl->CreateLabelLayoutItem(), 0, 1)
|
||||||
|
.Add(fSearchPageControl->CreateTextViewLayoutItem(), 1, 1)
|
||||||
|
|
||||||
|
.Add(fDownloadFolderControl->CreateLabelLayoutItem(), 0, 2)
|
||||||
|
.Add(fDownloadFolderControl->CreateTextViewLayoutItem(), 1, 2)
|
||||||
|
|
||||||
|
.Add(fNewWindowBehaviorMenu->CreateLabelLayoutItem(), 0, 3)
|
||||||
|
.Add(fNewWindowBehaviorMenu->CreateMenuBarLayoutItem(), 1, 3)
|
||||||
|
|
||||||
|
.Add(fNewTabBehaviorMenu->CreateLabelLayoutItem(), 0, 4)
|
||||||
|
.Add(fNewTabBehaviorMenu->CreateMenuBarLayoutItem(), 1, 4)
|
||||||
|
)
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing))
|
||||||
|
.Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing))
|
||||||
|
.Add(fShowTabsIfOnlyOnePage)
|
||||||
|
.Add(fAutoHideInterfaceInFullscreenMode)
|
||||||
|
.Add(fAutoHidePointer)
|
||||||
|
.Add(fShowHomeButton)
|
||||||
|
.Add(fDaysInHistoryMenuControl)
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing))
|
||||||
|
|
||||||
|
.SetInsets(spacing, spacing, spacing, spacing)
|
||||||
|
|
||||||
|
.TopView()
|
||||||
|
;
|
||||||
|
view->SetName(B_TRANSLATE("General"));
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
SettingsWindow::_CreateFontsPage(float spacing)
|
||||||
|
{
|
||||||
|
fStandardFontView = new FontSelectionView("standard",
|
||||||
|
B_TRANSLATE("Standard font:"), true, be_plain_font);
|
||||||
|
BFont defaultSerifFont = _FindDefaultSerifFont();
|
||||||
|
fSerifFontView = new FontSelectionView("serif",
|
||||||
|
B_TRANSLATE("Serif font:"), true, &defaultSerifFont);
|
||||||
|
fSansSerifFontView = new FontSelectionView("sans serif",
|
||||||
|
B_TRANSLATE("Sans serif font:"), true, be_plain_font);
|
||||||
|
fFixedFontView = new FontSelectionView("fixed",
|
||||||
|
B_TRANSLATE("Fixed font:"), true, be_fixed_font);
|
||||||
|
|
||||||
|
fStandardSizesMenu = new BMenuField("standard font size",
|
||||||
|
B_TRANSLATE("Default standard font size:"), new BPopUpMenu("sizes"),
|
||||||
|
B_WILL_DRAW);
|
||||||
|
_BuildSizesMenu(fStandardSizesMenu->Menu(),
|
||||||
|
MSG_STANDARD_FONT_SIZE_SELECTED);
|
||||||
|
|
||||||
|
fFixedSizesMenu = new BMenuField("fixed font size",
|
||||||
|
B_TRANSLATE("Default fixed font size:"), new BPopUpMenu("sizes"),
|
||||||
|
B_WILL_DRAW);
|
||||||
|
_BuildSizesMenu(fFixedSizesMenu->Menu(), MSG_FIXED_FONT_SIZE_SELECTED);
|
||||||
|
|
||||||
|
BView* view = BGridLayoutBuilder(spacing / 2, spacing / 2)
|
||||||
|
.Add(fStandardFontView->CreateFontsLabelLayoutItem(), 0, 0)
|
||||||
|
.Add(fStandardFontView->CreateFontsMenuBarLayoutItem(), 1, 0)
|
||||||
|
.Add(fStandardFontView->PreviewBox(), 0, 1, 2)
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing), 0, 2, 2)
|
||||||
|
|
||||||
|
.Add(fSerifFontView->CreateFontsLabelLayoutItem(), 0, 3)
|
||||||
|
.Add(fSerifFontView->CreateFontsMenuBarLayoutItem(), 1, 3)
|
||||||
|
.Add(fSerifFontView->PreviewBox(), 0, 4, 2)
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing), 0, 5, 2)
|
||||||
|
|
||||||
|
.Add(fSansSerifFontView->CreateFontsLabelLayoutItem(), 0, 6)
|
||||||
|
.Add(fSansSerifFontView->CreateFontsMenuBarLayoutItem(), 1, 6)
|
||||||
|
.Add(fSansSerifFontView->PreviewBox(), 0, 7, 2)
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing), 0, 8, 2)
|
||||||
|
|
||||||
|
.Add(fFixedFontView->CreateFontsLabelLayoutItem(), 0, 9)
|
||||||
|
.Add(fFixedFontView->CreateFontsMenuBarLayoutItem(), 1, 9)
|
||||||
|
.Add(fFixedFontView->PreviewBox(), 0, 10, 2)
|
||||||
|
.Add(BSpaceLayoutItem::CreateHorizontalStrut(spacing), 0, 11, 2)
|
||||||
|
|
||||||
|
.Add(fStandardSizesMenu->CreateLabelLayoutItem(), 0, 12)
|
||||||
|
.Add(fStandardSizesMenu->CreateMenuBarLayoutItem(), 1, 12)
|
||||||
|
.Add(fFixedSizesMenu->CreateLabelLayoutItem(), 0, 13)
|
||||||
|
.Add(fFixedSizesMenu->CreateMenuBarLayoutItem(), 1, 13)
|
||||||
|
|
||||||
|
.SetInsets(spacing, spacing, spacing, spacing)
|
||||||
|
|
||||||
|
.View()
|
||||||
|
;
|
||||||
|
|
||||||
|
view->SetName(B_TRANSLATE("Fonts"));
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
SettingsWindow::_CreateProxyPage(float spacing)
|
||||||
|
{
|
||||||
|
fUseProxyCheckBox = new BCheckBox("use proxy",
|
||||||
|
B_TRANSLATE("Use proxy server to connect to the internet."),
|
||||||
|
new BMessage(MSG_USE_PROXY_CHANGED));
|
||||||
|
fUseProxyCheckBox->SetValue(B_CONTROL_ON);
|
||||||
|
|
||||||
|
fProxyAddressControl = new BTextControl("proxy address",
|
||||||
|
B_TRANSLATE("Proxy server address:"), "",
|
||||||
|
new BMessage(MSG_PROXY_ADDRESS_CHANGED));
|
||||||
|
fProxyAddressControl->SetModificationMessage(
|
||||||
|
new BMessage(MSG_PROXY_ADDRESS_CHANGED));
|
||||||
|
fProxyAddressControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeyProxyAddress, ""));
|
||||||
|
|
||||||
|
fProxyPortControl = new BTextControl("proxy port",
|
||||||
|
B_TRANSLATE("Proxy server port:"), "",
|
||||||
|
new BMessage(MSG_PROXY_PORT_CHANGED));
|
||||||
|
fProxyPortControl->SetModificationMessage(
|
||||||
|
new BMessage(MSG_PROXY_PORT_CHANGED));
|
||||||
|
fProxyPortControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeyProxyAddress, ""));
|
||||||
|
|
||||||
|
BView* view = BGroupLayoutBuilder(B_VERTICAL, spacing / 2)
|
||||||
|
.Add(fUseProxyCheckBox)
|
||||||
|
.Add(BGridLayoutBuilder(spacing / 2, spacing / 2)
|
||||||
|
.Add(fProxyAddressControl->CreateLabelLayoutItem(), 0, 0)
|
||||||
|
.Add(fProxyAddressControl->CreateTextViewLayoutItem(), 1, 0)
|
||||||
|
|
||||||
|
.Add(fProxyPortControl->CreateLabelLayoutItem(), 0, 1)
|
||||||
|
.Add(fProxyPortControl->CreateTextViewLayoutItem(), 1, 1)
|
||||||
|
)
|
||||||
|
.Add(BSpaceLayoutItem::CreateGlue())
|
||||||
|
|
||||||
|
.SetInsets(spacing, spacing, spacing, spacing)
|
||||||
|
|
||||||
|
.TopView()
|
||||||
|
;
|
||||||
|
view->SetName(B_TRANSLATE("Proxy server"));
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::_BuildSizesMenu(BMenu* menu, uint32 messageWhat)
|
||||||
|
{
|
||||||
|
const float kMinSize = 8.0;
|
||||||
|
const float kMaxSize = 18.0;
|
||||||
|
|
||||||
|
const int32 kSizes[] = {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 21, 24, 0};
|
||||||
|
|
||||||
|
for (int32 i = 0; kSizes[i]; i++) {
|
||||||
|
int32 size = kSizes[i];
|
||||||
|
if (size < kMinSize || size > kMaxSize)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char label[32];
|
||||||
|
snprintf(label, sizeof(label), "%ld", size);
|
||||||
|
|
||||||
|
BMessage* message = new BMessage(messageWhat);
|
||||||
|
message->AddInt32("size", size);
|
||||||
|
|
||||||
|
BMenuItem* item = new BMenuItem(label, message);
|
||||||
|
|
||||||
|
menu->AddItem(item);
|
||||||
|
item->SetTarget(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::_SetupFontSelectionView(FontSelectionView* view,
|
||||||
|
BMessage* message)
|
||||||
|
{
|
||||||
|
AddHandler(view);
|
||||||
|
view->AttachedToLooper();
|
||||||
|
view->SetMessage(message);
|
||||||
|
view->SetTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsWindow::_CanApplySettings() const
|
||||||
|
{
|
||||||
|
bool canApply = false;
|
||||||
|
|
||||||
|
// General settings
|
||||||
|
canApply = canApply || (strcmp(fStartPageControl->Text(),
|
||||||
|
fSettings->GetValue(kSettingsKeyStartPageURL,
|
||||||
|
kDefaultStartPageURL)) != 0);
|
||||||
|
|
||||||
|
canApply = canApply || (strcmp(fSearchPageControl->Text(),
|
||||||
|
fSettings->GetValue(kSettingsKeySearchPageURL,
|
||||||
|
kDefaultSearchPageURL)) != 0);
|
||||||
|
|
||||||
|
canApply = canApply || (strcmp(fDownloadFolderControl->Text(),
|
||||||
|
fSettings->GetValue(kSettingsKeyDownloadPath,
|
||||||
|
kDefaultDownloadPath)) != 0);
|
||||||
|
|
||||||
|
canApply = canApply || ((fShowTabsIfOnlyOnePage->Value() == B_CONTROL_ON)
|
||||||
|
!= fSettings->GetValue(kSettingsKeyShowTabsIfSinglePageOpen, true));
|
||||||
|
|
||||||
|
canApply = canApply || (
|
||||||
|
(fAutoHideInterfaceInFullscreenMode->Value() == B_CONTROL_ON)
|
||||||
|
!= fSettings->GetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
|
||||||
|
false));
|
||||||
|
|
||||||
|
canApply = canApply || (
|
||||||
|
(fAutoHidePointer->Value() == B_CONTROL_ON)
|
||||||
|
!= fSettings->GetValue(kSettingsKeyAutoHidePointer, false));
|
||||||
|
|
||||||
|
canApply = canApply || ((fShowHomeButton->Value() == B_CONTROL_ON)
|
||||||
|
!= fSettings->GetValue(kSettingsKeyShowHomeButton, true));
|
||||||
|
|
||||||
|
canApply = canApply || (_MaxHistoryAge()
|
||||||
|
!= BrowsingHistory::DefaultInstance()->MaxHistoryItemAge());
|
||||||
|
|
||||||
|
// New window policy
|
||||||
|
canApply = canApply || (_NewWindowPolicy()
|
||||||
|
!= fSettings->GetValue(kSettingsKeyNewWindowPolicy,
|
||||||
|
(uint32)OpenStartPage));
|
||||||
|
|
||||||
|
// New tab policy
|
||||||
|
canApply = canApply || (_NewTabPolicy()
|
||||||
|
!= fSettings->GetValue(kSettingsKeyNewTabPolicy,
|
||||||
|
(uint32)OpenBlankPage));
|
||||||
|
|
||||||
|
// Font settings
|
||||||
|
canApply = canApply || (fStandardFontView->Font()
|
||||||
|
!= fSettings->GetValue("standard font", *be_plain_font));
|
||||||
|
|
||||||
|
canApply = canApply || (fSerifFontView->Font()
|
||||||
|
!= fSettings->GetValue("serif font", _FindDefaultSerifFont()));
|
||||||
|
|
||||||
|
canApply = canApply || (fSansSerifFontView->Font()
|
||||||
|
!= fSettings->GetValue("sans serif font", *be_plain_font));
|
||||||
|
|
||||||
|
canApply = canApply || (fFixedFontView->Font()
|
||||||
|
!= fSettings->GetValue("fixed font", *be_fixed_font));
|
||||||
|
|
||||||
|
canApply = canApply || (_SizesMenuValue(fStandardSizesMenu->Menu())
|
||||||
|
!= fSettings->GetValue("standard font size", kDefaultFontSize));
|
||||||
|
|
||||||
|
canApply = canApply || (_SizesMenuValue(fFixedSizesMenu->Menu())
|
||||||
|
!= fSettings->GetValue("fixed font size", kDefaultFontSize));
|
||||||
|
|
||||||
|
// Proxy settings
|
||||||
|
canApply = canApply || ((fUseProxyCheckBox->Value() == B_CONTROL_ON)
|
||||||
|
!= fSettings->GetValue(kSettingsKeyUseProxy, false));
|
||||||
|
|
||||||
|
canApply = canApply || (strcmp(fProxyAddressControl->Text(),
|
||||||
|
fSettings->GetValue(kSettingsKeyProxyAddress, "")) != 0);
|
||||||
|
|
||||||
|
canApply = canApply || (_ProxyPort()
|
||||||
|
!= fSettings->GetValue(kSettingsKeyProxyPort, (uint32)0));
|
||||||
|
|
||||||
|
return canApply;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::_ApplySettings()
|
||||||
|
{
|
||||||
|
// Store general settings
|
||||||
|
int32 maxHistoryAge = _MaxHistoryAge();
|
||||||
|
BString text;
|
||||||
|
text << maxHistoryAge;
|
||||||
|
fDaysInHistoryMenuControl->SetText(text.String());
|
||||||
|
BrowsingHistory::DefaultInstance()->SetMaxHistoryItemAge(maxHistoryAge);
|
||||||
|
|
||||||
|
fSettings->SetValue(kSettingsKeyStartPageURL, fStartPageControl->Text());
|
||||||
|
fSettings->SetValue(kSettingsKeySearchPageURL, fSearchPageControl->Text());
|
||||||
|
fSettings->SetValue(kSettingsKeyDownloadPath, fDownloadFolderControl->Text());
|
||||||
|
fSettings->SetValue(kSettingsKeyShowTabsIfSinglePageOpen,
|
||||||
|
fShowTabsIfOnlyOnePage->Value() == B_CONTROL_ON);
|
||||||
|
fSettings->SetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
|
||||||
|
fAutoHideInterfaceInFullscreenMode->Value() == B_CONTROL_ON);
|
||||||
|
fSettings->SetValue(kSettingsKeyAutoHidePointer,
|
||||||
|
fAutoHidePointer->Value() == B_CONTROL_ON);
|
||||||
|
fSettings->SetValue(kSettingsKeyShowHomeButton,
|
||||||
|
fShowHomeButton->Value() == B_CONTROL_ON);
|
||||||
|
|
||||||
|
// New page policies
|
||||||
|
fSettings->SetValue(kSettingsKeyNewWindowPolicy, _NewWindowPolicy());
|
||||||
|
fSettings->SetValue(kSettingsKeyNewTabPolicy, _NewTabPolicy());
|
||||||
|
|
||||||
|
// Store fond settings
|
||||||
|
fSettings->SetValue("standard font", fStandardFontView->Font());
|
||||||
|
fSettings->SetValue("serif font", fSerifFontView->Font());
|
||||||
|
fSettings->SetValue("sans serif font", fSansSerifFontView->Font());
|
||||||
|
fSettings->SetValue("fixed font", fFixedFontView->Font());
|
||||||
|
int32 standardFontSize = _SizesMenuValue(fStandardSizesMenu->Menu());
|
||||||
|
int32 fixedFontSize = _SizesMenuValue(fFixedSizesMenu->Menu());
|
||||||
|
fSettings->SetValue("standard font size", standardFontSize);
|
||||||
|
fSettings->SetValue("fixed font size", fixedFontSize);
|
||||||
|
|
||||||
|
// Store proxy settings
|
||||||
|
|
||||||
|
fSettings->SetValue(kSettingsKeyUseProxy,
|
||||||
|
fUseProxyCheckBox->Value() == B_CONTROL_ON);
|
||||||
|
fSettings->SetValue(kSettingsKeyProxyAddress,
|
||||||
|
fProxyAddressControl->Text());
|
||||||
|
uint32 proxyPort = _ProxyPort();
|
||||||
|
fSettings->SetValue(kSettingsKeyProxyPort, proxyPort);
|
||||||
|
|
||||||
|
fSettings->Save();
|
||||||
|
|
||||||
|
// Apply settings to default web page settings.
|
||||||
|
BWebSettings::Default()->SetStandardFont(fStandardFontView->Font());
|
||||||
|
BWebSettings::Default()->SetSerifFont(fSerifFontView->Font());
|
||||||
|
BWebSettings::Default()->SetSansSerifFont(fSansSerifFontView->Font());
|
||||||
|
BWebSettings::Default()->SetFixedFont(fFixedFontView->Font());
|
||||||
|
BWebSettings::Default()->SetDefaultStandardFontSize(standardFontSize);
|
||||||
|
BWebSettings::Default()->SetDefaultFixedFontSize(fixedFontSize);
|
||||||
|
|
||||||
|
if (fUseProxyCheckBox->Value() == B_CONTROL_ON) {
|
||||||
|
BWebSettings::Default()->SetProxyInfo(fProxyAddressControl->Text(),
|
||||||
|
proxyPort, B_PROXY_TYPE_HTTP, "", "");
|
||||||
|
} else
|
||||||
|
BWebSettings::Default()->SetProxyInfo();
|
||||||
|
|
||||||
|
// This will find all currently instantiated page settings and apply
|
||||||
|
// the default values, unless the page settings have local overrides.
|
||||||
|
BWebSettings::Default()->Apply();
|
||||||
|
|
||||||
|
|
||||||
|
_ValidateControlsEnabledStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::_RevertSettings()
|
||||||
|
{
|
||||||
|
fStartPageControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeyStartPageURL, kDefaultStartPageURL));
|
||||||
|
|
||||||
|
fSearchPageControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeySearchPageURL, kDefaultSearchPageURL));
|
||||||
|
|
||||||
|
fDownloadFolderControl->SetText(
|
||||||
|
fSettings->GetValue(kSettingsKeyDownloadPath, kDefaultDownloadPath));
|
||||||
|
fShowTabsIfOnlyOnePage->SetValue(
|
||||||
|
fSettings->GetValue(kSettingsKeyShowTabsIfSinglePageOpen, true));
|
||||||
|
fAutoHideInterfaceInFullscreenMode->SetValue(
|
||||||
|
fSettings->GetValue(kSettingsKeyAutoHideInterfaceInFullscreenMode,
|
||||||
|
false));
|
||||||
|
fAutoHidePointer->SetValue(
|
||||||
|
fSettings->GetValue(kSettingsKeyAutoHidePointer, false));
|
||||||
|
fShowHomeButton->SetValue(
|
||||||
|
fSettings->GetValue(kSettingsKeyShowHomeButton, true));
|
||||||
|
|
||||||
|
BString text;
|
||||||
|
text << BrowsingHistory::DefaultInstance()->MaxHistoryItemAge();
|
||||||
|
fDaysInHistoryMenuControl->SetText(text.String());
|
||||||
|
|
||||||
|
// New window policy
|
||||||
|
uint32 newWindowPolicy = fSettings->GetValue(kSettingsKeyNewWindowPolicy,
|
||||||
|
(uint32)OpenStartPage);
|
||||||
|
switch (newWindowPolicy) {
|
||||||
|
default:
|
||||||
|
case OpenStartPage:
|
||||||
|
fNewWindowBehaviorOpenHomeItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
case OpenSearchPage:
|
||||||
|
fNewWindowBehaviorOpenSearchItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
case OpenBlankPage:
|
||||||
|
fNewWindowBehaviorOpenBlankItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New tab policy
|
||||||
|
uint32 newTabPolicy = fSettings->GetValue(kSettingsKeyNewTabPolicy,
|
||||||
|
(uint32)OpenBlankPage);
|
||||||
|
switch (newTabPolicy) {
|
||||||
|
default:
|
||||||
|
case OpenBlankPage:
|
||||||
|
fNewTabBehaviorOpenBlankItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
case OpenStartPage:
|
||||||
|
fNewTabBehaviorOpenHomeItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
case OpenSearchPage:
|
||||||
|
fNewTabBehaviorOpenSearchItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
case CloneCurrentPage:
|
||||||
|
fNewTabBehaviorCloneCurrentItem->SetMarked(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Font settings
|
||||||
|
int32 defaultFontSize = fSettings->GetValue("standard font size",
|
||||||
|
kDefaultFontSize);
|
||||||
|
int32 defaultFixedFontSize = fSettings->GetValue("fixed font size",
|
||||||
|
kDefaultFontSize);
|
||||||
|
|
||||||
|
_SetSizesMenuValue(fStandardSizesMenu->Menu(), defaultFontSize);
|
||||||
|
_SetSizesMenuValue(fFixedSizesMenu->Menu(), defaultFixedFontSize);
|
||||||
|
|
||||||
|
fStandardFontView->SetFont(fSettings->GetValue("standard font",
|
||||||
|
*be_plain_font), defaultFontSize);
|
||||||
|
fSerifFontView->SetFont(fSettings->GetValue("serif font",
|
||||||
|
_FindDefaultSerifFont()), defaultFontSize);
|
||||||
|
fSansSerifFontView->SetFont(fSettings->GetValue("sans serif font",
|
||||||
|
*be_plain_font), defaultFontSize);
|
||||||
|
fFixedFontView->SetFont(fSettings->GetValue("fixed font",
|
||||||
|
*be_fixed_font), defaultFixedFontSize);
|
||||||
|
|
||||||
|
// Proxy settings
|
||||||
|
fUseProxyCheckBox->SetValue(fSettings->GetValue(kSettingsKeyUseProxy,
|
||||||
|
false));
|
||||||
|
fProxyAddressControl->SetText(fSettings->GetValue(kSettingsKeyProxyAddress,
|
||||||
|
""));
|
||||||
|
text = "";
|
||||||
|
text << fSettings->GetValue(kSettingsKeyProxyPort, (uint32)0);
|
||||||
|
fProxyPortControl->SetText(text.String());
|
||||||
|
|
||||||
|
_ValidateControlsEnabledStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::_ValidateControlsEnabledStatus()
|
||||||
|
{
|
||||||
|
bool canApply = _CanApplySettings();
|
||||||
|
fApplyButton->SetEnabled(canApply);
|
||||||
|
fRevertButton->SetEnabled(canApply);
|
||||||
|
// Let the Cancel button be enabled always, as another way to close the
|
||||||
|
// window...
|
||||||
|
fCancelButton->SetEnabled(true);
|
||||||
|
|
||||||
|
bool useProxy = fUseProxyCheckBox->Value() == B_CONTROL_ON;
|
||||||
|
fProxyAddressControl->SetEnabled(useProxy);
|
||||||
|
fProxyPortControl->SetEnabled(useProxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
SettingsWindow::_NewWindowPolicy() const
|
||||||
|
{
|
||||||
|
uint32 newWindowPolicy = OpenStartPage;
|
||||||
|
BMenuItem* markedItem = fNewWindowBehaviorMenu->Menu()->FindMarked();
|
||||||
|
if (markedItem == fNewWindowBehaviorOpenSearchItem)
|
||||||
|
newWindowPolicy = OpenSearchPage;
|
||||||
|
else if (markedItem == fNewWindowBehaviorOpenBlankItem)
|
||||||
|
newWindowPolicy = OpenBlankPage;
|
||||||
|
return newWindowPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
SettingsWindow::_NewTabPolicy() const
|
||||||
|
{
|
||||||
|
uint32 newTabPolicy = OpenBlankPage;
|
||||||
|
BMenuItem* markedItem = fNewTabBehaviorMenu->Menu()->FindMarked();
|
||||||
|
if (markedItem == fNewTabBehaviorCloneCurrentItem)
|
||||||
|
newTabPolicy = CloneCurrentPage;
|
||||||
|
else if (markedItem == fNewTabBehaviorOpenHomeItem)
|
||||||
|
newTabPolicy = OpenStartPage;
|
||||||
|
else if (markedItem == fNewTabBehaviorOpenSearchItem)
|
||||||
|
newTabPolicy = OpenSearchPage;
|
||||||
|
return newTabPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
SettingsWindow::_MaxHistoryAge() const
|
||||||
|
{
|
||||||
|
int32 maxHistoryAge = atoi(fDaysInHistoryMenuControl->Text());
|
||||||
|
if (maxHistoryAge <= 0)
|
||||||
|
maxHistoryAge = 1;
|
||||||
|
if (maxHistoryAge >= 35)
|
||||||
|
maxHistoryAge = 35;
|
||||||
|
return maxHistoryAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsWindow::_SetSizesMenuValue(BMenu* menu, int32 value)
|
||||||
|
{
|
||||||
|
for (int32 i = 0; BMenuItem* item = menu->ItemAt(i); i++) {
|
||||||
|
bool marked = false;
|
||||||
|
if (BMessage* message = item->Message()) {
|
||||||
|
int32 size;
|
||||||
|
if (message->FindInt32("size", &size) == B_OK && size == value)
|
||||||
|
marked = true;
|
||||||
|
}
|
||||||
|
item->SetMarked(marked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
SettingsWindow::_SizesMenuValue(BMenu* menu) const
|
||||||
|
{
|
||||||
|
if (BMenuItem* item = menu->FindMarked()) {
|
||||||
|
if (BMessage* message = item->Message()) {
|
||||||
|
int32 size;
|
||||||
|
if (message->FindInt32("size", &size) == B_OK)
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kDefaultFontSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BFont
|
||||||
|
SettingsWindow::_FindDefaultSerifFont() const
|
||||||
|
{
|
||||||
|
// Default to the first "serif" font we find.
|
||||||
|
BFont serifFont(*be_plain_font);
|
||||||
|
font_family family;
|
||||||
|
int32 familyCount = count_font_families();
|
||||||
|
for (int32 i = 0; i < familyCount; i++) {
|
||||||
|
if (get_font_family(i, &family) == B_OK) {
|
||||||
|
BString familyString(family);
|
||||||
|
if (familyString.IFindFirst("sans") >= 0)
|
||||||
|
continue;
|
||||||
|
if (familyString.IFindFirst("serif") >= 0) {
|
||||||
|
serifFont.SetFamilyAndFace(family, B_REGULAR_FACE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return serifFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
SettingsWindow::_ProxyPort() const
|
||||||
|
{
|
||||||
|
return atoul(fProxyPortControl->Text());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef SETTINGS_WINDOW_H
|
||||||
|
#define SETTINGS_WINDOW_H
|
||||||
|
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
class BButton;
|
||||||
|
class BCheckBox;
|
||||||
|
class BMenu;
|
||||||
|
class BMenuField;
|
||||||
|
class BMenuItem;
|
||||||
|
class BTextControl;
|
||||||
|
class FontSelectionView;
|
||||||
|
class SettingsMessage;
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsWindow : public BWindow {
|
||||||
|
public:
|
||||||
|
SettingsWindow(BRect frame,
|
||||||
|
SettingsMessage* settings);
|
||||||
|
virtual ~SettingsWindow();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
virtual bool QuitRequested();
|
||||||
|
|
||||||
|
virtual void Show();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BView* _CreateGeneralPage(float spacing);
|
||||||
|
BView* _CreateFontsPage(float spacing);
|
||||||
|
BView* _CreateProxyPage(float spacing);
|
||||||
|
void _BuildSizesMenu(BMenu* menu,
|
||||||
|
uint32 messageWhat);
|
||||||
|
void _SetupFontSelectionView(
|
||||||
|
FontSelectionView* view,
|
||||||
|
BMessage* message);
|
||||||
|
|
||||||
|
bool _CanApplySettings() const;
|
||||||
|
void _ApplySettings();
|
||||||
|
void _RevertSettings();
|
||||||
|
void _ValidateControlsEnabledStatus();
|
||||||
|
|
||||||
|
uint32 _NewWindowPolicy() const;
|
||||||
|
uint32 _NewTabPolicy() const;
|
||||||
|
int32 _MaxHistoryAge() const;
|
||||||
|
|
||||||
|
void _SetSizesMenuValue(BMenu* menu, int32 value);
|
||||||
|
int32 _SizesMenuValue(BMenu* menu) const;
|
||||||
|
|
||||||
|
BFont _FindDefaultSerifFont() const;
|
||||||
|
|
||||||
|
uint32 _ProxyPort() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SettingsMessage* fSettings;
|
||||||
|
|
||||||
|
BTextControl* fStartPageControl;
|
||||||
|
BTextControl* fSearchPageControl;
|
||||||
|
BTextControl* fDownloadFolderControl;
|
||||||
|
|
||||||
|
BMenuField* fNewWindowBehaviorMenu;
|
||||||
|
BMenuItem* fNewWindowBehaviorOpenHomeItem;
|
||||||
|
BMenuItem* fNewWindowBehaviorOpenSearchItem;
|
||||||
|
BMenuItem* fNewWindowBehaviorOpenBlankItem;
|
||||||
|
|
||||||
|
BMenuField* fNewTabBehaviorMenu;
|
||||||
|
BMenuItem* fNewTabBehaviorCloneCurrentItem;
|
||||||
|
BMenuItem* fNewTabBehaviorOpenHomeItem;
|
||||||
|
BMenuItem* fNewTabBehaviorOpenSearchItem;
|
||||||
|
BMenuItem* fNewTabBehaviorOpenBlankItem;
|
||||||
|
|
||||||
|
BTextControl* fDaysInHistoryMenuControl;
|
||||||
|
BCheckBox* fShowTabsIfOnlyOnePage;
|
||||||
|
BCheckBox* fAutoHideInterfaceInFullscreenMode;
|
||||||
|
BCheckBox* fAutoHidePointer;
|
||||||
|
BCheckBox* fShowHomeButton;
|
||||||
|
|
||||||
|
FontSelectionView* fStandardFontView;
|
||||||
|
FontSelectionView* fSerifFontView;
|
||||||
|
FontSelectionView* fSansSerifFontView;
|
||||||
|
FontSelectionView* fFixedFontView;
|
||||||
|
|
||||||
|
BCheckBox* fUseProxyCheckBox;
|
||||||
|
BTextControl* fProxyAddressControl;
|
||||||
|
BTextControl* fProxyPortControl;
|
||||||
|
|
||||||
|
BButton* fApplyButton;
|
||||||
|
BButton* fCancelButton;
|
||||||
|
BButton* fRevertButton;
|
||||||
|
|
||||||
|
BMenuField* fStandardSizesMenu;
|
||||||
|
BMenuField* fFixedSizesMenu;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SETTINGS_WINDOW_H
|
||||||
|
|
||||||
@@ -0,0 +1,654 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Stephan Aßmus <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "URLInputGroup.h"
|
||||||
|
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <Clipboard.h>
|
||||||
|
#include <GroupLayout.h>
|
||||||
|
#include <GroupLayoutBuilder.h>
|
||||||
|
#include <LayoutUtils.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <SeparatorView.h>
|
||||||
|
#include <TextView.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "BaseURL.h"
|
||||||
|
#include "BitmapButton.h"
|
||||||
|
#include "BrowsingHistory.h"
|
||||||
|
#include "IconButton.h"
|
||||||
|
#include "TextViewCompleter.h"
|
||||||
|
|
||||||
|
|
||||||
|
class URLChoice : public BAutoCompleter::Choice {
|
||||||
|
public:
|
||||||
|
URLChoice(const BString& choiceText, const BString& displayText,
|
||||||
|
int32 matchPos, int32 matchLen, int32 priority)
|
||||||
|
:
|
||||||
|
BAutoCompleter::Choice(choiceText, displayText, matchPos, matchLen),
|
||||||
|
fPriority(priority)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const URLChoice& other) const
|
||||||
|
{
|
||||||
|
if (fPriority > other.fPriority)
|
||||||
|
return true;
|
||||||
|
return DisplayText() < other.DisplayText();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const URLChoice& other) const
|
||||||
|
{
|
||||||
|
return fPriority == other.fPriority
|
||||||
|
&& DisplayText() < other.DisplayText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 fPriority;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BrowsingHistoryChoiceModel : public BAutoCompleter::ChoiceModel {
|
||||||
|
virtual void FetchChoicesFor(const BString& pattern)
|
||||||
|
{
|
||||||
|
int32 count = CountChoices();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
delete reinterpret_cast<BAutoCompleter::Choice*>(
|
||||||
|
fChoices.ItemAtFast(i));
|
||||||
|
}
|
||||||
|
fChoices.MakeEmpty();
|
||||||
|
|
||||||
|
// Search through BrowsingHistory for any matches.
|
||||||
|
BrowsingHistory* history = BrowsingHistory::DefaultInstance();
|
||||||
|
if (!history->Lock())
|
||||||
|
return;
|
||||||
|
|
||||||
|
BString lastBaseURL;
|
||||||
|
int32 priority = INT_MAX;
|
||||||
|
|
||||||
|
count = history->CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BrowsingHistoryItem item = history->HistoryItemAt(i);
|
||||||
|
const BString& choiceText = item.URL();
|
||||||
|
int32 matchPos = choiceText.IFindFirst(pattern);
|
||||||
|
if (matchPos < 0)
|
||||||
|
continue;
|
||||||
|
if (lastBaseURL.Length() > 0
|
||||||
|
&& choiceText.FindFirst(lastBaseURL) >= 0) {
|
||||||
|
priority--;
|
||||||
|
} else
|
||||||
|
priority = INT_MAX;
|
||||||
|
lastBaseURL = baseURL(choiceText);
|
||||||
|
fChoices.AddItem(new URLChoice(choiceText,
|
||||||
|
choiceText, matchPos, pattern.Length(), priority));
|
||||||
|
}
|
||||||
|
|
||||||
|
history->Unlock();
|
||||||
|
|
||||||
|
fChoices.SortItems(_CompareChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int32 CountChoices() const
|
||||||
|
{
|
||||||
|
return fChoices.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const BAutoCompleter::Choice* ChoiceAt(int32 index) const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<BAutoCompleter::Choice*>(
|
||||||
|
fChoices.ItemAt(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _CompareChoices(const void* a, const void* b)
|
||||||
|
{
|
||||||
|
const URLChoice* aChoice
|
||||||
|
= *reinterpret_cast<const URLChoice* const *>(a);
|
||||||
|
const URLChoice* bChoice
|
||||||
|
= *reinterpret_cast<const URLChoice* const *>(b);
|
||||||
|
if (*aChoice < *bChoice)
|
||||||
|
return -1;
|
||||||
|
else if (*aChoice == *bChoice)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BList fChoices;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - URLTextView
|
||||||
|
|
||||||
|
|
||||||
|
static const float kHorizontalTextRectInset = 4.0;
|
||||||
|
|
||||||
|
|
||||||
|
class URLInputGroup::URLTextView : public BTextView {
|
||||||
|
private:
|
||||||
|
static const uint32 MSG_CLEAR = 'cler';
|
||||||
|
|
||||||
|
public:
|
||||||
|
URLTextView(URLInputGroup* parent);
|
||||||
|
virtual ~URLTextView();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
virtual void FrameResized(float width, float height);
|
||||||
|
virtual void MouseDown(BPoint where);
|
||||||
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
virtual void MakeFocus(bool focused = true);
|
||||||
|
|
||||||
|
virtual BSize MinSize();
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
|
||||||
|
void SetUpdateAutoCompleterChoices(bool update);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void InsertText(const char* inText, int32 inLength,
|
||||||
|
int32 inOffset,
|
||||||
|
const text_run_array* inRuns);
|
||||||
|
virtual void DeleteText(int32 fromOffset, int32 toOffset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _AlignTextRect();
|
||||||
|
|
||||||
|
private:
|
||||||
|
URLInputGroup* fURLInputGroup;
|
||||||
|
TextViewCompleter* fURLAutoCompleter;
|
||||||
|
BString fPreviousText;
|
||||||
|
bool fUpdateAutoCompleterChoices;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
URLInputGroup::URLTextView::URLTextView(URLInputGroup* parent)
|
||||||
|
:
|
||||||
|
BTextView("url"),
|
||||||
|
fURLInputGroup(parent),
|
||||||
|
fURLAutoCompleter(new TextViewCompleter(this,
|
||||||
|
new BrowsingHistoryChoiceModel())),
|
||||||
|
fPreviousText(""),
|
||||||
|
fUpdateAutoCompleterChoices(true)
|
||||||
|
{
|
||||||
|
MakeResizable(true);
|
||||||
|
SetStylable(true);
|
||||||
|
fURLAutoCompleter->SetModificationsReported(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
URLInputGroup::URLTextView::~URLTextView()
|
||||||
|
{
|
||||||
|
delete fURLAutoCompleter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case MSG_CLEAR:
|
||||||
|
SetText("");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BTextView::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::FrameResized(float width, float height)
|
||||||
|
{
|
||||||
|
BTextView::FrameResized(width, height);
|
||||||
|
_AlignTextRect();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::MouseDown(BPoint where)
|
||||||
|
{
|
||||||
|
bool wasFocus = IsFocus();
|
||||||
|
if (!wasFocus)
|
||||||
|
MakeFocus(true);
|
||||||
|
|
||||||
|
int32 buttons;
|
||||||
|
if (Window()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK)
|
||||||
|
buttons = B_PRIMARY_MOUSE_BUTTON;
|
||||||
|
|
||||||
|
if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
|
||||||
|
// Display context menu
|
||||||
|
int32 selectionStart;
|
||||||
|
int32 selectionEnd;
|
||||||
|
GetSelection(&selectionStart, &selectionEnd);
|
||||||
|
bool canCutOrCopy = selectionEnd > selectionStart;
|
||||||
|
|
||||||
|
bool canPaste = false;
|
||||||
|
if (be_clipboard->Lock()) {
|
||||||
|
if (BMessage* data = be_clipboard->Data())
|
||||||
|
canPaste = data->HasData("text/plain", B_MIME_TYPE);
|
||||||
|
be_clipboard->Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
BMenuItem* cutItem = new BMenuItem("Cut", new BMessage(B_CUT));
|
||||||
|
BMenuItem* copyItem = new BMenuItem("Copy", new BMessage(B_COPY));
|
||||||
|
BMenuItem* pasteItem = new BMenuItem("Paste", new BMessage(B_PASTE));
|
||||||
|
BMenuItem* clearItem = new BMenuItem("Clear", new BMessage(MSG_CLEAR));
|
||||||
|
cutItem->SetEnabled(canCutOrCopy);
|
||||||
|
copyItem->SetEnabled(canCutOrCopy);
|
||||||
|
pasteItem->SetEnabled(canPaste);
|
||||||
|
clearItem->SetEnabled(strlen(Text()) > 0);
|
||||||
|
|
||||||
|
BPopUpMenu* menu = new BPopUpMenu("url context");
|
||||||
|
menu->AddItem(cutItem);
|
||||||
|
menu->AddItem(copyItem);
|
||||||
|
menu->AddItem(pasteItem);
|
||||||
|
menu->AddItem(clearItem);
|
||||||
|
|
||||||
|
menu->SetTargetForItems(this);
|
||||||
|
menu->Go(ConvertToScreen(where), true, true, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only pass through to base class if we already have focus.
|
||||||
|
if (!wasFocus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BTextView::MouseDown(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::KeyDown(const char* bytes, int32 numBytes)
|
||||||
|
{
|
||||||
|
switch (bytes[0]) {
|
||||||
|
case B_TAB:
|
||||||
|
BView::KeyDown(bytes, numBytes);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_ESCAPE:
|
||||||
|
// Revert to text as it was when we received keyboard focus.
|
||||||
|
SetText(fPreviousText.String());
|
||||||
|
SelectAll();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_RETURN:
|
||||||
|
// Don't let this through to the text view.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
BTextView::KeyDown(bytes, numBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::MakeFocus(bool focus)
|
||||||
|
{
|
||||||
|
if (focus == IsFocus())
|
||||||
|
return;
|
||||||
|
|
||||||
|
BTextView::MakeFocus(focus);
|
||||||
|
|
||||||
|
if (focus) {
|
||||||
|
fPreviousText = Text();
|
||||||
|
SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
fURLInputGroup->Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
URLInputGroup::URLTextView::MinSize()
|
||||||
|
{
|
||||||
|
BSize min;
|
||||||
|
min.height = ceilf(LineHeight(0) + kHorizontalTextRectInset);
|
||||||
|
// we always add at least one pixel vertical inset top/bottom for
|
||||||
|
// the text rect.
|
||||||
|
min.width = min.height * 3;
|
||||||
|
return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
URLInputGroup::URLTextView::MaxSize()
|
||||||
|
{
|
||||||
|
BSize max(MinSize());
|
||||||
|
max.width = B_SIZE_UNLIMITED;
|
||||||
|
return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::SetUpdateAutoCompleterChoices(bool update)
|
||||||
|
{
|
||||||
|
fUpdateAutoCompleterChoices = update;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::InsertText(const char* inText, int32 inLength,
|
||||||
|
int32 inOffset, const text_run_array* inRuns)
|
||||||
|
{
|
||||||
|
// Filter all line breaks, note that inText is not terminated.
|
||||||
|
if (inLength == 1) {
|
||||||
|
if (*inText == '\n' || *inText == '\r')
|
||||||
|
BTextView::InsertText(" ", 1, inOffset, inRuns);
|
||||||
|
else
|
||||||
|
BTextView::InsertText(inText, 1, inOffset, inRuns);
|
||||||
|
} else {
|
||||||
|
BString filteredText(inText, inLength);
|
||||||
|
filteredText.ReplaceAll('\n', ' ');
|
||||||
|
filteredText.ReplaceAll('\r', ' ');
|
||||||
|
BTextView::InsertText(filteredText.String(), inLength, inOffset,
|
||||||
|
inRuns);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the base URL part bold.
|
||||||
|
BString text(Text(), TextLength());
|
||||||
|
int32 baseUrlStart = text.FindFirst("://");
|
||||||
|
if (baseUrlStart >= 0)
|
||||||
|
baseUrlStart += 3;
|
||||||
|
else
|
||||||
|
baseUrlStart = 0;
|
||||||
|
int32 baseUrlEnd = text.FindFirst("/", baseUrlStart);
|
||||||
|
if (baseUrlEnd < 0)
|
||||||
|
baseUrlEnd = TextLength();
|
||||||
|
BFont font;
|
||||||
|
GetFont(&font);
|
||||||
|
const rgb_color black = (rgb_color){ 0, 0, 0, 255 };
|
||||||
|
const rgb_color gray = (rgb_color){ 60, 60, 60, 255 };
|
||||||
|
if (baseUrlStart > 0)
|
||||||
|
SetFontAndColor(0, baseUrlStart - 1, &font, B_FONT_ALL, &gray);
|
||||||
|
if (baseUrlEnd > baseUrlStart) {
|
||||||
|
font.SetFace(B_BOLD_FACE);
|
||||||
|
SetFontAndColor(baseUrlStart, baseUrlEnd, &font, B_FONT_ALL, &black);
|
||||||
|
}
|
||||||
|
if (baseUrlEnd < TextLength()) {
|
||||||
|
font.SetFace(B_REGULAR_FACE);
|
||||||
|
SetFontAndColor(baseUrlEnd, TextLength(), &font, B_FONT_ALL, &gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
fURLAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::DeleteText(int32 fromOffset, int32 toOffset)
|
||||||
|
{
|
||||||
|
BTextView::DeleteText(fromOffset, toOffset);
|
||||||
|
|
||||||
|
fURLAutoCompleter->TextModified(fUpdateAutoCompleterChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::URLTextView::_AlignTextRect()
|
||||||
|
{
|
||||||
|
// Layout the text rect to be in the middle, normally this means there
|
||||||
|
// is one pixel spacing on each side.
|
||||||
|
BRect textRect(Bounds());
|
||||||
|
textRect.left = 0.0;
|
||||||
|
float vInset = max_c(1,
|
||||||
|
floorf((textRect.Height() - LineHeight(0)) / 2.0 + 0.5));
|
||||||
|
float hInset = kHorizontalTextRectInset;
|
||||||
|
|
||||||
|
if (be_control_look)
|
||||||
|
hInset = be_control_look->DefaultLabelSpacing();
|
||||||
|
|
||||||
|
textRect.InsetBy(hInset, vInset);
|
||||||
|
SetTextRect(textRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uint32 kGoBitmapWidth = 14;
|
||||||
|
const uint32 kGoBitmapHeight = 14;
|
||||||
|
const color_space kGoBitmapFormat = B_RGBA32;
|
||||||
|
|
||||||
|
const unsigned char kGoBitmapBits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x2f, 0x2f, 0x2f, 0x56, 0x50, 0x50, 0x50, 0xff, 0x4d, 0x4d, 0x4d, 0xed,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21,
|
||||||
|
0x49, 0x49, 0x49, 0xe0, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x37, 0x37, 0x37, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe0, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x50, 0x50, 0x50, 0xff, 0x4b, 0x4b, 0x4b, 0xec, 0x37, 0x37, 0x37, 0x77, 0x00, 0x00, 0x00, 0x02,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe1, 0x50, 0x50, 0x50, 0xff, 0x50, 0x50, 0x50, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21,
|
||||||
|
0x49, 0x49, 0x49, 0xe1, 0x50, 0x50, 0x50, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x49, 0x49, 0x49, 0xe1,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x17, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - PageIconView
|
||||||
|
|
||||||
|
|
||||||
|
class URLInputGroup::PageIconView : public BView {
|
||||||
|
public:
|
||||||
|
PageIconView()
|
||||||
|
:
|
||||||
|
BView("page icon view", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
|
||||||
|
fIcon(NULL)
|
||||||
|
{
|
||||||
|
SetDrawingMode(B_OP_ALPHA);
|
||||||
|
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PageIconView()
|
||||||
|
{
|
||||||
|
delete fIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
if (fIcon == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BRect bounds(Bounds());
|
||||||
|
BRect iconBounds(0, 0, 15, 15);
|
||||||
|
iconBounds.OffsetTo(
|
||||||
|
floorf((bounds.left + bounds.right
|
||||||
|
- (iconBounds.left + iconBounds.right)) / 2 + 0.5f),
|
||||||
|
floorf((bounds.top + bounds.bottom
|
||||||
|
- (iconBounds.top + iconBounds.bottom)) / 2 + 0.5f));
|
||||||
|
DrawBitmap(fIcon, fIcon->Bounds(), iconBounds,
|
||||||
|
B_FILTER_BITMAP_BILINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
if (fIcon != NULL)
|
||||||
|
return BSize(18, 18);
|
||||||
|
return BSize(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetIcon(const BBitmap* icon)
|
||||||
|
{
|
||||||
|
if (icon == NULL && fIcon == NULL)
|
||||||
|
return;
|
||||||
|
if (!(fIcon != NULL && icon != NULL))
|
||||||
|
InvalidateLayout();
|
||||||
|
delete fIcon;
|
||||||
|
if (icon)
|
||||||
|
fIcon = new BBitmap(icon);
|
||||||
|
else
|
||||||
|
fIcon = NULL;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BBitmap* fIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - URLInputGroup
|
||||||
|
|
||||||
|
|
||||||
|
URLInputGroup::URLInputGroup(BMessage* goMessage)
|
||||||
|
:
|
||||||
|
BGroupView(B_HORIZONTAL, 0.0),
|
||||||
|
fWindowActive(false)
|
||||||
|
{
|
||||||
|
GroupLayout()->SetInsets(2, 2, 2, 2);
|
||||||
|
|
||||||
|
fIconView = new PageIconView();
|
||||||
|
GroupLayout()->AddView(fIconView, 0.0f);
|
||||||
|
|
||||||
|
fTextView = new URLTextView(this);
|
||||||
|
AddChild(fTextView);
|
||||||
|
|
||||||
|
AddChild(new BSeparatorView(B_VERTICAL, B_PLAIN_BORDER));
|
||||||
|
|
||||||
|
// TODO: Fix in Haiku, no in-built support for archived BBitmaps from
|
||||||
|
// resources?
|
||||||
|
// fGoButton = new BitmapButton("kActionGo", NULL);
|
||||||
|
fGoButton = new BitmapButton(kGoBitmapBits, kGoBitmapWidth,
|
||||||
|
kGoBitmapHeight, kGoBitmapFormat, goMessage);
|
||||||
|
GroupLayout()->AddView(fGoButton, 0.0f);
|
||||||
|
|
||||||
|
SetFlags(Flags() | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
|
||||||
|
SetLowColor(ViewColor());
|
||||||
|
SetViewColor(B_TRANSPARENT_COLOR);
|
||||||
|
|
||||||
|
SetExplicitAlignment(BAlignment(B_ALIGN_USE_FULL_WIDTH,
|
||||||
|
B_ALIGN_VERTICAL_CENTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
URLInputGroup::~URLInputGroup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::AttachedToWindow()
|
||||||
|
{
|
||||||
|
BGroupView::AttachedToWindow();
|
||||||
|
fWindowActive = Window()->IsActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::WindowActivated(bool active)
|
||||||
|
{
|
||||||
|
BGroupView::WindowActivated(active);
|
||||||
|
if (fWindowActive != active) {
|
||||||
|
fWindowActive = active;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect bounds(Bounds());
|
||||||
|
rgb_color base(LowColor());
|
||||||
|
uint32 flags = 0;
|
||||||
|
if (fWindowActive && fTextView->IsFocus())
|
||||||
|
flags |= BControlLook::B_FOCUSED;
|
||||||
|
be_control_look->DrawTextControlBorder(this, bounds, updateRect, base,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::MakeFocus(bool focus)
|
||||||
|
{
|
||||||
|
// Forward this to the text view, we never accept focus ourselves.
|
||||||
|
fTextView->MakeFocus(focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BTextView*
|
||||||
|
URLInputGroup::TextView() const
|
||||||
|
{
|
||||||
|
return fTextView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::SetText(const char* text)
|
||||||
|
{
|
||||||
|
if (!text || !Text() || strcmp(Text(), text) != 0) {
|
||||||
|
fTextView->SetUpdateAutoCompleterChoices(false);
|
||||||
|
fTextView->SetText(text);
|
||||||
|
fTextView->SetUpdateAutoCompleterChoices(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
URLInputGroup::Text() const
|
||||||
|
{
|
||||||
|
return fTextView->Text();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BButton*
|
||||||
|
URLInputGroup::GoButton() const
|
||||||
|
{
|
||||||
|
return fGoButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
URLInputGroup::SetPageIcon(const BBitmap* icon)
|
||||||
|
{
|
||||||
|
fIconView->SetIcon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Stephan Aßmus <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef URL_INPUT_GROUP_H
|
||||||
|
#define URL_INPUT_GROUP_H
|
||||||
|
|
||||||
|
#include <GroupView.h>
|
||||||
|
|
||||||
|
class BButton;
|
||||||
|
class BTextView;
|
||||||
|
|
||||||
|
|
||||||
|
class URLInputGroup : public BGroupView {
|
||||||
|
public:
|
||||||
|
URLInputGroup(BMessage* goMessage);
|
||||||
|
virtual ~URLInputGroup();
|
||||||
|
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
virtual void WindowActivated(bool active);
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
virtual void MakeFocus(bool focus = true);
|
||||||
|
|
||||||
|
BTextView* TextView() const;
|
||||||
|
void SetText(const char* text);
|
||||||
|
const char* Text() const;
|
||||||
|
|
||||||
|
BButton* GoButton() const;
|
||||||
|
|
||||||
|
void SetPageIcon(const BBitmap* icon);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class PageIconView;
|
||||||
|
class URLTextView;
|
||||||
|
|
||||||
|
PageIconView* fIconView;
|
||||||
|
URLTextView* fTextView;
|
||||||
|
BButton* fGoButton;
|
||||||
|
bool fWindowActive;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // URL_INPUT_GROUP_H
|
||||||
|
|
||||||
@@ -0,0 +1,350 @@
|
|||||||
|
resource app_signature "application/x-vnd.Haiku-WebPositive";
|
||||||
|
|
||||||
|
resource app_version {
|
||||||
|
major = 0,
|
||||||
|
middle = 0,
|
||||||
|
minor = 1,
|
||||||
|
variety = B_APPV_ALPHA,
|
||||||
|
internal = 0,
|
||||||
|
short_info = "WebPositive",
|
||||||
|
long_info = "WebPositive ©2007-2010 The WebKit Haiku Project"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource app_flags B_SINGLE_LAUNCH;
|
||||||
|
|
||||||
|
resource file_types message {
|
||||||
|
"types" = "text/html",
|
||||||
|
"types" = "image/svg+xml",
|
||||||
|
"types" = "application/x-vnd.Be.URL.file",
|
||||||
|
"types" = "application/x-vnd.Be.URL.ftp",
|
||||||
|
"types" = "application/x-vnd.Be.URL.http",
|
||||||
|
"types" = "application/x-vnd.Be.URL.https"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource vector_icon {
|
||||||
|
$"6E636966450500020106033D0AFE000000000000BD0AFE48F10748A0783133FF"
|
||||||
|
$"FFC80066FFFF0034CC020106033D0AFE000000000000BD0AFE48F10748A07854"
|
||||||
|
$"09B4B6D8033784FF051D61020106043D950B0000000000003D950B494FBC479B"
|
||||||
|
$"EC00FFFFFF4C00FF008F00B200FF008000050002030605B812A5BE03E13DE784"
|
||||||
|
$"B8021049F79F49EDD800F1F1F136D9DDF48A9996B9B4B8BEDBFFF4F4F404EBD0"
|
||||||
|
$"020006023C92C0388F5FB854503C576348D8DF48895B004137A9FFB9B9B90401"
|
||||||
|
$"7E03FF360003FFFF0003FF9C0003FF000002010202BB36AEBA1760B80FFF392B"
|
||||||
|
$"574ACCFB48652300000001FFFF0000013205400500020004024AFFFC00FFFFBA"
|
||||||
|
$"360500020106033D0AFE000000000000BD0AFE48F10748A0783133FFFFC80066"
|
||||||
|
$"FFFF0034CC020106023D0AFE000000000000BD0AFE48F10748A0780033FFFFFF"
|
||||||
|
$"0033CC020106023D0AFE000000000000BD0AFE48F10748A0780033FFFFFF0066"
|
||||||
|
$"FF020004027AFFFC00DDFFBA360201040289FF0000A9C000000200040200FFE5"
|
||||||
|
$"CED0ECB989020004020DEFBC8CFFD4AA820200040200FFCB9CE9ECB989020004"
|
||||||
|
$"0200FFCB9CE9ECB98902000402B3FFCB9CBBD4AA820500020106033D0AFE0000"
|
||||||
|
$"00000000BD0AFE48F10748A0783133FFFFC80066FFFF0034CC020106033D0AFE"
|
||||||
|
$"000000000000BD0AFE48F10748A0785409B4B6D8033784FF051D61020106043D"
|
||||||
|
$"950B0000000000003D950B494FBC479BEC00FFFFFF4C00FF008F00B200FF0080"
|
||||||
|
$"00050002030605B812A5BE03E13DE784B8021049F79F49EDD800F1F1F136D9DD"
|
||||||
|
$"F48A9996B9B4B8BEDBFFF4F4F404EBD0020006023C92C0388F5FB854503C5763"
|
||||||
|
$"48D8DF48895B004137A9FFB9B9B904017E03FF360003FFFF000200040200FFBC"
|
||||||
|
$"34FFFF9C0003FF000002010202BB36AEBA1760B80FFF392B574ACCFB48652300"
|
||||||
|
$"000001FFFF00000132054003FFFFC9020014020026FF1C0500050002030605B8"
|
||||||
|
$"12A5BE03E13DE784B8021049F79F49EDD800F1F1F136D9DDF48A9996B9B4B8BE"
|
||||||
|
$"DBFFF4F4F404EBD0020006023C92C0388F5FB854503C576348D8DF48895B0041"
|
||||||
|
$"37A9FFB9B9B904017E03FF360003FFFF0003FF9C0003FF000002010202BB36AE"
|
||||||
|
$"BA1760B80FFF392B574ACCFB48652300000001FFFF0000013205400500030052"
|
||||||
|
$"7502001002F8006BFF003E04006C050003900000020310020000006E00650400"
|
||||||
|
$"6B05000359463503C3A414039D816035000000000204BFC1B55A36B55AC3BEB5"
|
||||||
|
$"5AC6FABC92C6FAB895C6FAC08FBFC1C3CBC3BEC3CB36C3CBB889BC92B889C08F"
|
||||||
|
$"B889B895066EFFFFF30FFFFEFFFFBFBFFEFFFEFFFEFFFFFFFFBFFFEFDFFBFBFF"
|
||||||
|
$"FF0FC5DBB8B5C713BA9FC4CAB706C10FB579C307B5D4C0A226BFC1B55AC031B5"
|
||||||
|
$"5ABDBCB55ABA69B7BA36B63AB8F9B94EB89CBD9BB84EBB7EB8C7BE9AB924BF76"
|
||||||
|
$"B8E0BEE7B9DEC11FBCDFC332BB37C278BEC4C405C2D7C31AC0FAC3FCC2C5C2C0"
|
||||||
|
$"C22EC2B7C279C2BDC22EC2B7C226C240C2BDC240C2BDC206C2AFC199C2DAC1D0"
|
||||||
|
$"C2CB44C2EEC0D4C2DCC114C2E5C051C2CEBF42C312BFB0C2B4BF3DC312BF35BF"
|
||||||
|
$"1FBDECC312BE23C312BDB8C2EDBD57C2DEBD86C2E2BD53C2DBBD3EC2C2BD3EC2"
|
||||||
|
$"C2BD31C2B4BD12C2A4BD26C2AABD12C2A4BCA4C27EBC31C254BC31C254BC27C2"
|
||||||
|
$"51BC11C24FBC1DC250BC10C24BBC0FC241BC10C245BC0FC241BBF5C219BBF5C2"
|
||||||
|
$"19BBD2C1DDBB68C194BBADC1A4BB70C16EBB58C128BB62C14EBB4BC101BB4BC0"
|
||||||
|
$"ACBB47C0D7BB4BC0ACBB4EC087BB4EC087BB51C054BB4DBFEEBB54C021BB9DBF"
|
||||||
|
$"92BBA9BEBFBBAFBF35BBA9BEBFBBA7BE92BBA7BE92BBA7BE52BBBBBE2FBBA8BE"
|
||||||
|
$"4BBBBBBE2FBBC6BE20BBC6BE20BC00BDD4BBE2BCFBBC5BBD3DBBE2BCFBBAB7BC"
|
||||||
|
$"58BA8ABC43BA90BC45BA8ABC43BA8ABC42BA8ABC42BA88BBEABA22BB78BA6ABB"
|
||||||
|
$"ACBA22BB78BA12BB6AB9F8BB48B9ADBAEFB9ADBAEFB97DBAC3B927BAB0B94FBA"
|
||||||
|
$"B5B924BAA9B91ABA9AB920BAA0B984BA6DB9DEB996B9B5B9F9B9F6B95DBA36B8"
|
||||||
|
$"EFBA0AB91FBA5EB8C4BA78B85EBA83B89EBACCB83CBB60B7E7BB18B813BB60B7"
|
||||||
|
$"E7BB6AB7E1BBFEB787BBFEB787BC65B749BCB6B683BC93B6F5BCF5B689BD58B6"
|
||||||
|
$"64BD2CB67BBDA8B695BE6CB6503C29BE6FB64FBE88B64FBE7CB64FBE62B6A0BE"
|
||||||
|
$"E1B72FBE88B70EBEE4B733BEE8B73DBEE5B73ABED8B743BEC5B749BE74B7A5BE"
|
||||||
|
$"74B7A5BE63B7DCBE8FB848BE74B816BE90B84CBE91B852BE91B852BE93B85BBE"
|
||||||
|
$"9CB87ABE97B86BBE93B883BE8CB88DBE8CB88DBE39B8EFBD91B98FBDB6B906BD"
|
||||||
|
$"91B98FBD8DB9A0BD8DB9A0BD64B9D7BD7EBA54BD59BA19BD7ABA5CBD76BA62BD"
|
||||||
|
$"76BA62BD56BA9FBD4DBB2BBD38BAE6BD5FBB6FBDCCBBCEBD98BBA1BDFFBBF9BE"
|
||||||
|
$"73BC3FBE33BC27BEBEBC5CBF5DBC42BF11BC55BF5DBC42BFAB37BFAB37BFD0BC"
|
||||||
|
$"1DC01CBC0FBFF4BC0BC045BC13C083BC4EC066BC35C04DBCD9C0F3BDDAC0B6BD"
|
||||||
|
$"63C0F3BDDAC107BDF8C102BDF2C0BABE83C126BF90C0B1BF1CC126BF90C133BF"
|
||||||
|
$"9CC133BF9CC130C00EC1C4C0F8C135C0D6C258C11CC347C059C2EEC0C8C347C0"
|
||||||
|
$"59C36BC02EC388C018C388C018C3A7C003C3DABFC4C3C9BFE8C3EEBF9FC408BF"
|
||||||
|
$"51C3EFBF73C408BF51C408BF52C408BF52C40CBF99C49540C450BFCEC4EBBFB3"
|
||||||
|
$"C541BF0FC51FBF56C541BF0FC551BEF24EBEEA4EBEEAC57FBEA3C568BDFCC59E"
|
||||||
|
$"BE46C53ABDBAC4A2BDDEC4E0BDA9C4A2BDCABDB5C4A4BD31C4A4BD31C4A7BD1D"
|
||||||
|
$"C4E8BCDEC4D2BCF5C4E8BCDEC4FEBCC8C516BCB3C516BCB3C544BC8BC582BC1F"
|
||||||
|
$"C570BC5DC58BBC04C587BBBBC586BBD9C587BBBBC587BBA8C587BB9DC587BB9D"
|
||||||
|
$"C58CBB604EBAF9C584BB23C589BADAC5C1BA5DC5B0BAA1C5C3BA61C5CBBA6FC5"
|
||||||
|
$"CBBA6FC5D8BA8EC60EBAD3C5EDBAB3C609BB1EC648BBAAC626BB67C669BBEAC6"
|
||||||
|
$"6EBC7AC66FBC33C66EBC7AC671BCC3C671BCC3C673BCE9C66DBD36C677BD10C6"
|
||||||
|
$"64BD5AC649BD9BC652BD78C633BDEBC62BBE91C62DBE3F50BED5C67FBF2BC648"
|
||||||
|
$"BF16C750BD0F0006BC11B6E3BC11B6E3BC32B6AFBC54B637BC46B674BB81B6AA"
|
||||||
|
$"BA2BB801BAC4B747BA87B7E2BB2FB77DBADDB7AFBB59B764BBAAB733BB82B74D"
|
||||||
|
$"BBCBB71CBC11B6E3BBFBB707BC11B6E3001DBACDBFD1BACDBFD1BAEBBFA9BB29"
|
||||||
|
$"BF5BBB12BF89BB43BF24BB34BE92BB34BECFBB34BE4DBB5FBDE9BB34BE25BB80"
|
||||||
|
$"BDBEBBAABD5FBBA0BD98BB47BD29BA81BCBEBAE5BCF3BA67BCB1BA1FBC8332BC"
|
||||||
|
$"9FBA0FBC5BBA0DBC02BA1FBC28B9FDBBE5B9B9BBB6B9D0BBD0B99BBB91B95FBB"
|
||||||
|
$"44B983BB66B93DBB23B8EFBB2CB91BBB15B8C0BB47B8BEBADEB8C2BAFFB8B1BB"
|
||||||
|
$"13B89FBB7EB8A7BB48B8C8BB7EB8C5BBB2B8C2BB89B8C6BBDBB8C8BC2DB8C7BC"
|
||||||
|
$"04B8CFBC40B8BABC48B8CBBC48B8B3BC4BB8A9BC4EB8AEBC4DB8A0BC57B893BC"
|
||||||
|
$"4BB898BC55B881BC4AB88EBD0FB88DBD00B893BD49B8E0BDE7B88DBE02B90DBE"
|
||||||
|
$"03B922BE74B906BE4BB946BEA7B985BF00B972BEC1B996BF3EB9A240B997BF80"
|
||||||
|
$"B9AFC010BA16C05EB9DBC02DBA24C0B3BA75C126BA3CC0E7BA8FC143BAC0C17F"
|
||||||
|
$"BAA9C15FBAD7C19FBAFBC17BBAE3C19DBADDC13ABAD6C0A5BAD2C0EFBADBC060"
|
||||||
|
$"BACDBFD1BAEAC012BACDBFD10009BD5DB5D6BD5DB5D6BD81B5EDBDB1B60DBD83"
|
||||||
|
$"B605BDCFB613BE19B600BE01B619BE55B5C3BEF5B5C3BEB0B5EFBF2CB5A1BFA3"
|
||||||
|
$"B55D3FB55DBFCEB55DC00CB58CBFE9B577C03CB5A6C08FB566C063B574BF39B5"
|
||||||
|
$"40BCA7B60DBDDCB57ABCEBB623BD5DB5D6BD29B600BD5DB5D60005BF34B6E9BF"
|
||||||
|
$"34B6E9BF55B6EBBF99B6F5BF7BB702BFCEB6E0BF87B67CBF9BB693BF77B66DBF"
|
||||||
|
$"3CB663BF2FB623BF44B68FBF34B6E9BF6AB6CBBF34B6E90004BA06B87FBA06B8"
|
||||||
|
$"7FBA0BB867B9EEB84FB9FDB85FB982B8E4B8EFBA35B92CB987B97D31BA06B87F"
|
||||||
|
$"B974B8EFBA06B87F0066C6F6BC24C6F6BC24C6DBBB09C6002FC68AB9F1C5B9B8"
|
||||||
|
$"7BC4FFB79BC563B805C4CEB768C463B708C49AB736C452B6FBC427B6EFC43FB6"
|
||||||
|
$"E2C411B6FAC407B6C1C401B6D0C315B60FC0D0B56EC1F8B59AC0FAB58AC15EB5"
|
||||||
|
$"9CC130B589C170B5A1C178B5C9C19FB5BDC12CB5E2C08AB5C9C0D7B5C3C059B5"
|
||||||
|
$"CDC03FB60DC042B5DDC03DB629C03FB676C036B65CC04AB694C0B6B65EC0A7B6"
|
||||||
|
$"6FC0CDB643C0F1B619C0B0B607C108B64AC0D0B6B0C13AB6D5C0B5B6A7C066B6"
|
||||||
|
$"89C083B67CC063B689C05CB6AFC05EB6AAC053B6C0C030B6CFC043B6CABFE5B6"
|
||||||
|
$"E4BF94B741BFB0B6EFBF87B768BF5CB790BF88B781BF3BB79CBEF6B7B2BF17B7"
|
||||||
|
$"A3BECCB7C7BEF9B81BBEE9B7FFBF05B82FBF19B86CBF02B860BF59B891BFBEB7"
|
||||||
|
$"E0BFA3B801BFE0B7B3C038B7ADC008B7BCC04FB7A6C084B776C06CB76EC0D3B7"
|
||||||
|
$"95C0F7B83EC0EBB7F4C10FB83FC135B80FC100B801C10CB7E5C0ECB76F43B7AA"
|
||||||
|
$"C125B795C15EB7FCC14DB7BCC170B83CC1C1B820C18DB860C1CFB813C1FCB7D4"
|
||||||
|
$"C1E1B7BCC213B7E9C1F1B838C2142DC206B84BC23AB83CC222B842C259B83447"
|
||||||
|
$"B841C26CB835C2AEB84FC2F9B856C2D5B854C320B859C346B898C335B87AC376"
|
||||||
|
$"B8E6C249B8C5C258B8C6C227B8C2C1E1B8CFC202B8C1C1C8B8DAC199B8EFC1B6"
|
||||||
|
$"2FC178B8E5C13EB8B5C15AB8C7C117B89BC0C4B872C0EFB885C07EB853BFE2B8"
|
||||||
|
$"4EC02EB83FBFBFB855BF7FB87BBF9BB866BF5BB896BF10B8A4BF34B87FBEDBB8"
|
||||||
|
$"DBBE6DB941BEB5B91FBE50B94FBE19B976BE2DB95BBE03B990BDF5B9D1BE03B9"
|
||||||
|
$"B4BDE8B9EDBDE2BA1DBDCAB9FBBDF7BA3BBDEFBA76BDFEBA52BDD9BAA9BDC9BB"
|
||||||
|
$"27BD9EBAEEBDF235BE71BBBBBE39BB93BEAFBBE9BF40BBD1BEFBBBE5BF82BBC1"
|
||||||
|
$"C009BB9CBFC4BBA0C05EBB95C0DCBC03C0A1BBCDC104BC26C0F4BC67C113BC34"
|
||||||
|
$"C0D3BC9EC103BD00C0E8BCC7C11FBD3644BDA3C13CBD6CC166BDB9C182BDE8C1"
|
||||||
|
$"76BDCFC18DBE03C16DBE2CC17ABE15C152BE5DC13EBECEC13EBE97C13EBF0DC1"
|
||||||
|
$"85BF4CC15CBF24C1A9BF71C1A4BFE2C1A7BFB3C1A0C025C1DAC087C1B3C053C2"
|
||||||
|
$"15C08AC289C06CC253C086C2CBC04DC319BFDDC2E8C00EC346BFB0C386BF66C3"
|
||||||
|
$"77BFAAC396BF12C3FEBEBFC3C1BEF2C435BE8FC430BE0CC42DBE4DC432BDC0C4"
|
||||||
|
$"33BD21C428BD6CC43BBCDDC4AABC77C47EBCA7C4CDBC55C511BC03C505BC34C5"
|
||||||
|
$"19BBE7C512BBA8C51236C512BB92C51035C51ABB70C4F7BB29C47EBB2BC489BB"
|
||||||
|
$"5DC475BB0EC48ABB01C476BB13C4A1BAECC477BACDC48ABAD7C441BAACC3F0BA"
|
||||||
|
$"66C418BA9AC3CCBA36C390B9CAC3ADBA00C389B9BDC36CB93AC341B92DC39AB9"
|
||||||
|
$"4AC3E1B9A2C3C3B981C419B9DFC46DBA6AC44ABA1FC46EBA73C496BA89C48EBA"
|
||||||
|
$"85C4AFBA9CC4EABAA8C4CABAABC533BAA1C559BA1F4EBA60C56231C4E8B9AEC5"
|
||||||
|
$"1DB9DAC4CAB996C49EB958C4B6B975C48EB946C473B90DC466B92AC492B8F9C4"
|
||||||
|
$"BCB91CC49FB90BC4DFB932C52BB951C505B9444EB95EC5B4B96CC591B952C5C9"
|
||||||
|
$"B97BC5E7B9B8C5D8B9A1C5FEB9DCC626BA26C614BA00C644BA60C694BA9EC64D"
|
||||||
|
$"BA88C667BAE8C6B6BB83C693BB3FC6DEBBD3C6E3BC7BC6E4BC22C6E2BCCEC6D0"
|
||||||
|
$"BD78C6F4BD2BC6A6BDCCC69FBE9AC69FBE3EC6A0BE95C6A4BE88C6A2BE8DC6A1"
|
||||||
|
$"3DC6A0BEC0C696BEBEC6B2BEC3C6D5BE01C6D2BE15C6F5BD65C6F6BC24C700BC"
|
||||||
|
$"C3C6F6BC240008C301B7D8C301B7D8C2E6B7DBC2D4B7A3C2E8B7AEC2B1B792C2"
|
||||||
|
$"69B7B7C288B7A7C204B7EEC236B742C221B77BC239B73AC285B743C279B746C2"
|
||||||
|
$"A6B740C2F2B74EC2D7B730C30BB76AC33CB7A1C31FB787C35FB7C1C301B7D8C3"
|
||||||
|
$"1CB7D4C301B7D80004BB52C203BB52C203BB44C20CBB26C221BB37C21DBB54C2"
|
||||||
|
$"48BBB9C290BB86C26EBB91C265BB52C203BB84C226BB52C2030005C4F3BE2DC4"
|
||||||
|
$"F3BE2DC4D3BE57C48BBEA4C4A5BE75C46EBEDAC47DBF52C47DBF18C4B6BF37C4"
|
||||||
|
$"EDBEB8C4D0BEEBC502BE92C4F3BE2DC531BE48C4F3BE2D0009C212C326C212C3"
|
||||||
|
$"26C17FC38FBFF6C344C09DC332BFD0C348BF8DC36ABFABC350BF66C38BBF1FC3"
|
||||||
|
$"86BF56C386BEAFC386BDCDC386BE3EC386BEC1C3CBC0BFC3BABFC3C3DCC137C3"
|
||||||
|
$"A9C221C367C1AEC38DC229C364C261C32AC280C337C248C322C212C326C229C3"
|
||||||
|
$"31C212C32602024E284E2C542E4C324C30482E020250304C3252344C364E344C"
|
||||||
|
$"34020258B81858305C32543654324E300202583456365836563C5A3854380204"
|
||||||
|
$"BCD5C1F1BACDC36FBEA5C09BC4A6BFA6C360BE3CC67FC1B0C064C5ACC23AC444"
|
||||||
|
$"BE90C715B827C85CB961C9B8B682C68B0204C3CFC072C309BF45C521C2733DC6"
|
||||||
|
$"5EC0DDC4E4BC10C7F6B880C76BB8DAC831B841C6E2BC6FC2E2B880C5CDBE42C1"
|
||||||
|
$"890622AEAAE6BAEAAAAF9A0EB9E4C6DEB9CB50B985C672BA12C5CDBAABC593BA"
|
||||||
|
$"C54DBAB8C4BBBAEBC3C8BAABC37CBA85C0CBBC88BE0E36B8E6B993B8DA2EB874"
|
||||||
|
$"B92DB970B7AFBCD5BA52BCEEB87ABE3AB7AEBD61B7AEBF12B7AEBF852EBF92BA"
|
||||||
|
$"78C0D2BB91C49BBB6AC51ABC10C51ABBB6C51ABC5AC49BBCB6C21DBCC3BF9FBD"
|
||||||
|
$"CEBFCBC18BC1FCC323BF00C13E46C33BC196C43B46C3DBC12AC484C02BC493C0"
|
||||||
|
$"11C3EFC091C36FBE20C2BDBF40BC50C14ABBF74EBB8451BBE8C66EBA9EC6B906"
|
||||||
|
$"11AAAAA8BA02BBEFB9ECBB49BAB8BCC8BB9DBCE1BE4EBB70C018BC7BC0A5BE07"
|
||||||
|
$"BF73BE6044BF9FBF6CBDDBC06CBD0245BCAEC1C9BC2FBF40BAABBE0EBB04BF0D"
|
||||||
|
$"BB04BD82BB04BD14BAB8BCAEBA38060BBAAA2A31C653BA0BC6C4BB84C645BB2B"
|
||||||
|
$"C69FBBB6C614BBAFC5A0BBDDC309BC1DC163BCAEC0CABB70BFE5BAD7C0CABADE"
|
||||||
|
$"C36FBAE3C5C5060AAAAB0ABE46C125BF99C130BF80454448C1FCC394C21DC361"
|
||||||
|
$"C1C3C3F0C11EC447C052C493C02BC3EFC105C389BE67470605EA02BB37BAC5BB"
|
||||||
|
$"D6BA12B9ACB887B8E0B8ADB90BB869B887B939B920B96C0A05C16BBB91C473BB"
|
||||||
|
$"91C4D9BC36C4A6BCC3C16BBCE906078A2EBD4F2EBDB5B814BEA7BF402EBF4DBA"
|
||||||
|
$"45BE0EBB04BEA7BB2BBD8ABAE2BD29BA520607AA3A39B8EDBE012F3CB99F3EB9"
|
||||||
|
$"93BEDAB920BF99B946BE34B77BBFF5B7C239B74804032EBCE932BDCEBB2BBD34"
|
||||||
|
$"BB12BECDBB51BF4DBA380208CA68BA5FCB40BD02CA39B9D0CA0EB6BCCAF3B7AE"
|
||||||
|
$"C947B5E955B58A55B58A55B58AC843B841C8FFB76C53B953C718B814C6E62FC7"
|
||||||
|
$"4BB728C5A02FC601B84EC2703DC645BCB6C5ACBC1DC711BD82C89DBEE7C79E40"
|
||||||
|
$"C89DBEE7060ABFFB0FC6F1C097C625BFCBC6F1BFCB5A345C3758315A2E5A305A"
|
||||||
|
$"2C582A562E582C54305230C691B854C691B920C691B7DAC53ABAAB4FB9ACC501"
|
||||||
|
$"BB1EC46EBBF7C4ADBB9DC3FABCB6C56DBE0EC38EBE4EC64DBDF00207C86FBE74"
|
||||||
|
$"C86FBE74C7A3BDA8C78ABB44C80ABB28C71835C633BBB7C6D4BBEFC5DABB98C5"
|
||||||
|
$"01BB44C509BB79C4F1BAEDC3F4BC43C43EBBD1C4B4BC83C6FF38C63336C7CB3A"
|
||||||
|
$"C83CBE9AC5B3BF8DC908BD020202C6392F4DB9F9C66CBAC54DBBE24FBB16C46E"
|
||||||
|
$"BAEB0202C969B7CEC967B915CAFFB9E1543654324E300202583456365836C876"
|
||||||
|
$"BD8FC969BB84C7AABBF70604EAC2BD4448C110C32EC07EC361C17DC33CC0E4C3"
|
||||||
|
$"7BC1E30205C5ACB861C65E31C52BB75D50204E224E20C3E1BA5FC37BB94FC455"
|
||||||
|
$"BB91C606BD02C493BCB6C722BE0DCB1BBDA8CB97BDE4C79EBBF702044EB44BC4"
|
||||||
|
$"D4284EB5174BB9B9C408B8BAC43DBAD755BD4F4BBBD057BD4FC744BB77C818BC"
|
||||||
|
$"3B51BAC502034E28C4A1B847C53AB61650BA52C592B8A0C690BBAEC4E0BAAB59"
|
||||||
|
$"BD8FC4E0B7A104032EB77BC612B63CC969B50AC7AAB777CB35BCA9C99C04032E"
|
||||||
|
$"B965B906B953B7D4B8D3B86D31B748BAB82C0406BE0BB689BE67B5FDC04BB607"
|
||||||
|
$"BF7FB5F0C11CB689C1D7B65BC1A2B73BC2A3B85448B77BC33CB801C31EB70849"
|
||||||
|
$"B609C32304032EBDA8B887BEB4B76EBE10B775BFEC2BC059B8AD04032E28BE01"
|
||||||
|
$"B3FFC0D8B4253FB3D2C288B5BDC2FB0406FE0BC79EBB2BC8F5BBAAC840BB47C9"
|
||||||
|
$"EBBC2ECB26BDDBCB05BD14CB40BE74CA4FC07ECA99BFCACA0EC117C9CFC27CCA"
|
||||||
|
$"0EC1E3C998C30058C3890A04C6FFBB11C856BC50C8BCBCC3C889BD4F040CAAFA"
|
||||||
|
$"BABC6FC74BC091C699C303C5CDC3DAC54DC440C4CEC44EC382C1EAC303C237C3"
|
||||||
|
$"4DC1D5C2EEC05EC402C149C3DFBF754BBD87C460BD47C4F9BE46C513BE2D4DBE"
|
||||||
|
$"98C58BBDBAC5870608BAAABFECC1FC4448C1FCC394C21DC361C1C3C3F0C11EC4"
|
||||||
|
$"47C052C493C02BC3EFC105C389BED3C2BD0A04C369BC83C6D738C666BD1CC35B"
|
||||||
|
$"BD350A03B46542B4BE41B4BE420605AF03B6AFC969B63CC9F1B72FC8D0BE4155"
|
||||||
|
$"B821CA8DC11CC6FAC42DC5C5C55FC53ABE67C91DC1E8C7EAB86DCB260604EEBF"
|
||||||
|
$"CBBB51C1FCBBD0C13EBC43C29FBB6EC18BBAAB43BB1EC145BAF2C09ABB4B0A04"
|
||||||
|
$"30303050505050302C0A0001021240BAB100000000000040B755C6CCDBBE9979"
|
||||||
|
$"01178300040A0101020240BAB100000000000040B755C6CCDBBE99790A020103"
|
||||||
|
$"0240BAB100000000000040B755C6CCDBBE99790A030A05060708090A0C0D040B"
|
||||||
|
$"0240BAB100000000000040B755C6CCDBBE99790A110113124084473AE65BBB05"
|
||||||
|
$"39406A8F40BD7AC6ED3001178400040A00012712401CCA0000000000004031D6"
|
||||||
|
$"BEA7B4C5651401178100040A150112024046733A7FB6BABB05401508437714C3"
|
||||||
|
$"BB840A3B012E0A401CC92E6813AE6813401CC9C0B293C4BE831DFF0A11011412"
|
||||||
|
$"402E52374883B74883402E5243A84DC5C35901178200040A16011502402E5237"
|
||||||
|
$"4883B74883402E5243A84DC5C3590A17011602402E52374883B74883402E5243"
|
||||||
|
$"A84DC5C3590A18011702402E52374883B74883402E5243A84DC5C3590A170118"
|
||||||
|
$"02402E52374883B74883402E5243A84DC5C3590A1801190240268F36C1F1B73C"
|
||||||
|
$"D33FA9DD442903C369B00A1B011A02402E52374883B74883402E5243A84DC5C3"
|
||||||
|
$"590A2C011B02402E52374883B74883402E5243A84DC5C3590A11011C12402E52"
|
||||||
|
$"374883B74883402E5243A84DC5C35901178100040A20011D124018A13C2DD3BC"
|
||||||
|
$"6F843F776243040C3B35B701178400040A28011D024018A13C481BBC6F843FA1"
|
||||||
|
$"3143AD0CC180CE0A27011E024018A13C3669BC6F843F850B43AD0CBDA6830A26"
|
||||||
|
$"03212022023F94B53C057BBC14913F373546DE4E423FFC0A2B012202401CCA00"
|
||||||
|
$"0000000000401CCAC64FB846E7CF0A2B01230241774E3E9634BD97FB40685AC6"
|
||||||
|
$"A141CA33220A0001291240075E0000000000004029CCC0DC88C59D5C01178100"
|
||||||
|
$"040A2E0124123E3A7739EBE1BA96D53D1E7BC874E948577D01178400040A3601"
|
||||||
|
$"24023DE4F539818BBA43313CC9E6C7EFC848861D0A350125023DE4F539818BBA"
|
||||||
|
$"43313CC9E6C7EFC848861D0A340126023DE4F539D28CBA43313D0A55C7EFC848"
|
||||||
|
$"5E9A0A000128123FEA4E3675EFB6F2733F44E3440366C2D26601178200040A00"
|
||||||
|
$"012A12402E52374883B74883402E5241C554C5CE0401178100040A00012B1240"
|
||||||
|
$"1CCA000000000000401CCAC0623FC4B46E01178100040A00012C124031960000"
|
||||||
|
$"00000000401CCAC3AEA8C4B46E01178100040A3A012D02401CCA000000000000"
|
||||||
|
$"401CCAC0E971C4B46E0A3C012F0A401CCA000000000000401CCAC0E971C4B46E"
|
||||||
|
$"1DFF0A3B01300A3FEC520000000000003C6A0B41051D473FEE1DFF0A3E013102"
|
||||||
|
$"40FA05000000000000417C4D3E5061C9E26E0A3F013212401CCA000000000000"
|
||||||
|
$"401CCAC0E971C42D3C01178200040A4001330A401CCA000000000000401CCAC0"
|
||||||
|
$"E971C4B46E1DFF0A420134023600000000000000003600004890004AE8000A42"
|
||||||
|
$"0134023600000000000000003600004870004AE8000A43013402360000000000"
|
||||||
|
$"0000003600004850004AF8000A43013402360000000000000000360000487000"
|
||||||
|
$"4AF8000A430134023600000000000000003600004890004AF8000A4401340236"
|
||||||
|
$"0000000000000000360000485000466000"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource(201, "kActionBack") #'VICN' array {
|
||||||
|
$"6E636966070500020006023B2FA63AC896BCCBD33D335A4A6980490D0B00ACE2"
|
||||||
|
$"FFFF6ECDFF0200060236D841374D6EBD38553CC6154AA9DF4607770026A8EBFF"
|
||||||
|
$"0694DE020006023729EA388C8FBC29073AAE614A51AF4A729A00035E8CFF0585"
|
||||||
|
$"C70200060238E8A83647FBBA8E2D3D42294AF6F7496CE200047BB8FF0694DE02"
|
||||||
|
$"0006023957BB3923F0BC39AC3C5E604AA873475AB1000592DAFD67CBFF04FF49"
|
||||||
|
$"080A092E3C3A53424C484F5047503A4435442B3A300A072E3C3A533A48484F48"
|
||||||
|
$"403A3A3A300A043A303A3A4435442B0A033A483A53424C0A044840484F504750"
|
||||||
|
$"3A0A043A3A4435503A48400803C125B7D43AB99FB8D3BE0E08023A3A4840070A"
|
||||||
|
$"0001001001178400040A010101000A020102000A030103000A040104000A0501"
|
||||||
|
$"05000A06020607100117812004"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource(202, "kActionForward") #'VICN' array {
|
||||||
|
$"6E636966050500020006023B2FA63AC896BCCBD33D335A4A6980490D0B00ACE2"
|
||||||
|
$"FFFF6ECDFF0200060239AF2C39E19BBC89D83C68DC4AFA1247CFA20006A5F7FF"
|
||||||
|
$"069EEC02000602B8EEBEB986C33C7FB4BC13FB46FA0C49FBDD000592DAFD3EBD"
|
||||||
|
$"FF04FF49050A0A2E423A483A524847503F432A3A2F3A3136302E350A0748473A"
|
||||||
|
$"2F3A392E352E423A483A520A043A2F4847503F432A0A042E3536303A313A3908"
|
||||||
|
$"0536B9932FBB773B3A3BB939C0E5B755050A0001001001178400040A01010100"
|
||||||
|
$"0A020102000A030103000A040104100117812004"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource(203, "kActionForward2") #'VICN' array {
|
||||||
|
$"6E63696607050002000602396DF23A056B3B94FCBB09F547CD484AAB5F0090D9"
|
||||||
|
$"FFFF6ECDFF02000602B5E5793878A83E023B3B2AC34893F147CC490060C8FFFF"
|
||||||
|
$"44BEFD02000602B6F90538542D3C2FCA3ACA9249A8634A929A00034F77FF0468"
|
||||||
|
$"9C020006023AC62E392AB63B6BA0BCFF0B49DAAA4AAE4500046FA7FF2BA5E502"
|
||||||
|
$"0006023A1CB834EBA6383E33BD3E8D499DE44A647800ACE2FFFD6DCCFF04FF49"
|
||||||
|
$"080A09523A48533F503C532E4C2E3E3A363A2B482E0A07523A485348473C533C"
|
||||||
|
$"43483A482E0A04482E483A3A363A2B0A03484748533F500A043C433C532E4C2E"
|
||||||
|
$"3E0A04483A3A362E3E3C430802BD8FB795C2BDB8E008023C43B8C7BF0D070A00"
|
||||||
|
$"01001001178400040A040101000A020102000A030103000A010104000A050105"
|
||||||
|
$"000A06020607100117812004"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource(204, "kActionStop") #'VICN' array {
|
||||||
|
$"6E63696606050102000602393D323BB602BEA28F3C4CC64B601449439F00FF3E"
|
||||||
|
$"3EFFF70606020006033B27153C10C7BDF9893D088A4B2F634882C500C805057D"
|
||||||
|
$"9D0404FFB4040403750303020006023B06EB3B5469BC08EB3BB31F4AB15D4478"
|
||||||
|
$"7700FF9090FFFF757504FF440A0A0C2E4C364E3C4742524A5440434A3842353C"
|
||||||
|
$"BE1B36312E2E38400A0636313C3C40434A54504E402E0A03364E3E483C470A04"
|
||||||
|
$"483FC712BADE4A3840430A042E2E3631402E382C0A0442354A38C712BADE4AB9"
|
||||||
|
$"EC0A0E2E4C364EBEB6C37042524A54504E483FC712BADE4AB9EC4335402E382C"
|
||||||
|
$"2E2E384008022FB8A0BCC3B80708033C3C42364ABA120802BCA9BFF3B8D3C47B"
|
||||||
|
$"060A0001061001178400040A020101000A03020302000A010100000A04020504"
|
||||||
|
$"000A0503070809100117810004"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource(206, "kActionGoStart") #'VICN' array {
|
||||||
|
$"6E63696605050002001602B53D77BAF2653D77A7B7CFFC460F874A2D7700F0FF"
|
||||||
|
$"D50200160236FB2637191CBC57873C40E14B0E7149D82700A2FFBB0200060239"
|
||||||
|
$"FB483A6DC2BDAC713D02DB4B384746086300EA0606FFD005050200060238B0C7"
|
||||||
|
$"397C47BD2A963C71B74A82C348B2B700FF4444FFF106060A0A06304942525044"
|
||||||
|
$"50383E32303D0A09303B3049324A32C0723643364C4252424036320A04503650"
|
||||||
|
$"44425242400A082D3E3535434645455439462C35312B3C0A062B3C2D3E353543"
|
||||||
|
$"46454535310A0445455439462C35310A0432C072324A364C36430A043A453A4A"
|
||||||
|
$"3E4C3EC2630A044645464A484848430A044C3F4C444E424E3D070A0001001001"
|
||||||
|
$"178400040A010101000A020102000A000406070809000A000103100117840004"
|
||||||
|
$"0A030105000A04010400"
|
||||||
|
};
|
||||||
|
|
||||||
|
resource(205, "kActionGo") archive BBitmap {
|
||||||
|
"_frame" = rect { 0.0, 0.0, 15.0, 15.0 },
|
||||||
|
"_cspace" = 8200,
|
||||||
|
"_bmflags" = 0,
|
||||||
|
"_rowbytes" = 64,
|
||||||
|
"_data" = array {
|
||||||
|
$"0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000C1000000DE00000061000000070000000100000000"
|
||||||
|
$"0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000FF9BD4A5FF48634EFF000000C00000003500000004"
|
||||||
|
$"0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000FFB6F9C2FFB3F9C0FF84B68EFF263426FD0000009B"
|
||||||
|
$"0000001600000002000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000FFB6F9C2FF7EF995FFA3F9B3FFAAE9B6FF69906FFF"
|
||||||
|
$"000000E200000064000000070000000100000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000FFB6F9C2FF6AFB85FF6AFB85FF83FA98FFA4F5B2FF"
|
||||||
|
$"7CC88AFF325C3BFF000000C00000003500000004000000000000000000000000"
|
||||||
|
$"0000000000000000000000FFB6F9C2FF5DFC7BFF5DFC7BFF5DFC7BFF5DFB7CFF"
|
||||||
|
$"60ED7AFF54D76DFF389A48FF002A14FD0000009B000000160000000200000000"
|
||||||
|
$"0000000000000000000000FFB5F8C1FF59FC77FF59FC77FF59FC77FF59FC77FF"
|
||||||
|
$"59FC77FF55F674FF40DB5CFF2BBC48FF1C752BFF000000D00000002000000003"
|
||||||
|
$"0000000000000000000000FFA8F4B5FF2EFA54FF2EFA54FF2EFA54FF2EFA54FF"
|
||||||
|
$"2EFA54FF2BF350FF22D542FF1CB638FF157027FF000000D00000003D00000009"
|
||||||
|
$"0000000000000000000000FF92ECA2FF15F940FF15F940FF15F940FF15F740FF"
|
||||||
|
$"15DE35FF00BE2EFF008922FF002600FD0000009B000000430000002000000003"
|
||||||
|
$"0000000000000000000000FF7EE591FF15F83DFF15F83DFF1CEA3DFF00C732FF"
|
||||||
|
$"009E22FF004815FF000000BF000000560000002D0000000F0000000200000000"
|
||||||
|
$"0000000000000000000000FF6DDF81FF1CF340FF2BDA4AFF1CB638FF006D1CFF"
|
||||||
|
$"000000E200000074000000360000001900000004000000000000000000000000"
|
||||||
|
$"0000000000000000000000FF5DDA75FF44D25FFF229338FF002600FD0000009B"
|
||||||
|
$"0000004300000023000000070000000100000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000FF46B65CFF1C5222FF000000BF000000560000002D"
|
||||||
|
$"0000000F00000002000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000C2000000DE00000074000000360000001900000004"
|
||||||
|
$"0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
$"0000000000000000000000030000001F00000020000000080000000100000000"
|
||||||
|
$"0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Oliver Tappe <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AutoCompleter.h"
|
||||||
|
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <Message.h>
|
||||||
|
|
||||||
|
#include "AutoCompleterDefaultImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DefaultPatternSelector
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultPatternSelector : public BAutoCompleter::PatternSelector {
|
||||||
|
public:
|
||||||
|
virtual void SelectPatternBounds(const BString& text, int32 caretPos,
|
||||||
|
int32* start, int32* length);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DefaultPatternSelector::SelectPatternBounds(const BString& text,
|
||||||
|
int32 caretPos, int32* start, int32* length)
|
||||||
|
{
|
||||||
|
if (!start || !length)
|
||||||
|
return;
|
||||||
|
*start = 0;
|
||||||
|
*length = text.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - CompletionStyle
|
||||||
|
|
||||||
|
|
||||||
|
BAutoCompleter::CompletionStyle::CompletionStyle(EditView* editView,
|
||||||
|
ChoiceModel* choiceModel, ChoiceView* choiceView,
|
||||||
|
PatternSelector* patternSelector)
|
||||||
|
:
|
||||||
|
fEditView(editView),
|
||||||
|
fPatternSelector(patternSelector ? patternSelector
|
||||||
|
: new DefaultPatternSelector()),
|
||||||
|
fChoiceModel(choiceModel),
|
||||||
|
fChoiceView(choiceView)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAutoCompleter::CompletionStyle::~CompletionStyle()
|
||||||
|
{
|
||||||
|
delete fEditView;
|
||||||
|
delete fChoiceModel;
|
||||||
|
delete fChoiceView;
|
||||||
|
delete fPatternSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::CompletionStyle::SetEditView(EditView* view)
|
||||||
|
{
|
||||||
|
delete fEditView;
|
||||||
|
fEditView = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::CompletionStyle::SetPatternSelector(
|
||||||
|
PatternSelector* selector)
|
||||||
|
{
|
||||||
|
delete fPatternSelector;
|
||||||
|
fPatternSelector = selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::CompletionStyle::SetChoiceModel(ChoiceModel* model)
|
||||||
|
{
|
||||||
|
delete fChoiceModel;
|
||||||
|
fChoiceModel = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::CompletionStyle::SetChoiceView(ChoiceView* view)
|
||||||
|
{
|
||||||
|
delete fChoiceView;
|
||||||
|
fChoiceView = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BAutoCompleter
|
||||||
|
|
||||||
|
|
||||||
|
BAutoCompleter::BAutoCompleter(CompletionStyle* completionStyle)
|
||||||
|
:
|
||||||
|
fCompletionStyle(completionStyle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAutoCompleter::BAutoCompleter(EditView* editView, ChoiceModel* choiceModel,
|
||||||
|
ChoiceView* choiceView, PatternSelector* patternSelector)
|
||||||
|
:
|
||||||
|
fCompletionStyle(new BDefaultCompletionStyle(editView, choiceModel,
|
||||||
|
choiceView, patternSelector))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAutoCompleter::~BAutoCompleter()
|
||||||
|
{
|
||||||
|
delete fCompletionStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BAutoCompleter::Select(int32 index)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
return fCompletionStyle->Select(index);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BAutoCompleter::SelectNext(bool wrap)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
return fCompletionStyle->SelectNext(wrap);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BAutoCompleter::SelectPrevious(bool wrap)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
return fCompletionStyle->SelectPrevious(wrap);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BAutoCompleter::IsChoiceSelected() const
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
return fCompletionStyle->IsChoiceSelected();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BAutoCompleter::CountChoices() const
|
||||||
|
{
|
||||||
|
if (fCompletionStyle && fCompletionStyle->GetChoiceModel())
|
||||||
|
return fCompletionStyle->GetChoiceModel()->CountChoices();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BAutoCompleter::CountVisibleChoices() const
|
||||||
|
{
|
||||||
|
if (fCompletionStyle && fCompletionStyle->GetChoiceView())
|
||||||
|
return fCompletionStyle->GetChoiceView()->CountVisibleChoices();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BAutoCompleter::SelectedChoiceIndex() const
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
return fCompletionStyle->SelectedChoiceIndex();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::ApplyChoice(bool hideChoices)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->ApplyChoice(hideChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::CancelChoice()
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->CancelChoice();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::EditViewStateChanged(bool updateChoices)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->EditViewStateChanged(updateChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::SetEditView(EditView* view)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->SetEditView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::SetPatternSelector(PatternSelector* selector)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->SetPatternSelector(selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::SetChoiceModel(ChoiceModel* model)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->SetChoiceModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::SetChoiceView(ChoiceView* view)
|
||||||
|
{
|
||||||
|
if (fCompletionStyle)
|
||||||
|
fCompletionStyle->SetChoiceView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BAutoCompleter::SetCompletionStyle(CompletionStyle* style)
|
||||||
|
{
|
||||||
|
delete fCompletionStyle;
|
||||||
|
fCompletionStyle = style;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Oliver Tappe <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef _AUTO_COMPLETER_H
|
||||||
|
#define _AUTO_COMPLETER_H
|
||||||
|
|
||||||
|
#include <MessageFilter.h>
|
||||||
|
|
||||||
|
#include <Rect.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
class BAutoCompleter {
|
||||||
|
public:
|
||||||
|
class Choice {
|
||||||
|
public:
|
||||||
|
Choice(const BString& choiceText,
|
||||||
|
const BString& displayText, int32 matchPos,
|
||||||
|
int32 matchLen)
|
||||||
|
:
|
||||||
|
fText(choiceText),
|
||||||
|
fDisplayText(displayText),
|
||||||
|
fMatchPos(matchPos),
|
||||||
|
fMatchLen(matchLen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~Choice() {}
|
||||||
|
const BString& Text() const { return fText; }
|
||||||
|
const BString& DisplayText() const { return fDisplayText; }
|
||||||
|
int32 MatchPos() const { return fMatchPos; }
|
||||||
|
int32 MatchLen() const { return fMatchLen; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fText;
|
||||||
|
BString fDisplayText;
|
||||||
|
int32 fMatchPos;
|
||||||
|
int32 fMatchLen;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditView {
|
||||||
|
public:
|
||||||
|
virtual ~EditView() {}
|
||||||
|
|
||||||
|
virtual BRect GetAdjustmentFrame() = 0;
|
||||||
|
virtual void GetEditViewState(BString& text,
|
||||||
|
int32* caretPos) = 0;
|
||||||
|
virtual void SetEditViewState(const BString& text,
|
||||||
|
int32 caretPos,
|
||||||
|
int32 selectionLength = 0) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatternSelector {
|
||||||
|
public:
|
||||||
|
virtual ~PatternSelector() {}
|
||||||
|
|
||||||
|
virtual void SelectPatternBounds(const BString& text,
|
||||||
|
int32 caretPos, int32* start,
|
||||||
|
int32* length) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChoiceModel {
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~ChoiceModel() {}
|
||||||
|
|
||||||
|
virtual void FetchChoicesFor(const BString& pattern) = 0;
|
||||||
|
|
||||||
|
virtual int32 CountChoices() const = 0;
|
||||||
|
virtual const Choice* ChoiceAt(int32 index) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompletionStyle;
|
||||||
|
class ChoiceView {
|
||||||
|
public:
|
||||||
|
virtual ~ChoiceView() {}
|
||||||
|
|
||||||
|
virtual void SelectChoiceAt(int32 index) = 0;
|
||||||
|
virtual void ShowChoices(
|
||||||
|
BAutoCompleter::CompletionStyle* completer)
|
||||||
|
= 0;
|
||||||
|
virtual void HideChoices() = 0;
|
||||||
|
virtual bool ChoicesAreShown() = 0;
|
||||||
|
virtual int32 CountVisibleChoices() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompletionStyle {
|
||||||
|
public:
|
||||||
|
CompletionStyle(EditView* editView,
|
||||||
|
ChoiceModel* choiceModel,
|
||||||
|
ChoiceView* choiceView,
|
||||||
|
PatternSelector* patternSelector);
|
||||||
|
virtual ~CompletionStyle();
|
||||||
|
|
||||||
|
virtual bool Select(int32 index) = 0;
|
||||||
|
virtual bool SelectNext(bool wrap = false) = 0;
|
||||||
|
virtual bool SelectPrevious(bool wrap = false) = 0;
|
||||||
|
virtual bool IsChoiceSelected() const = 0;
|
||||||
|
virtual int32 SelectedChoiceIndex() const = 0;
|
||||||
|
|
||||||
|
virtual void ApplyChoice(bool hideChoices = true) = 0;
|
||||||
|
virtual void CancelChoice() = 0;
|
||||||
|
|
||||||
|
virtual void EditViewStateChanged(bool updateChoices) = 0;
|
||||||
|
|
||||||
|
void SetEditView(EditView* view);
|
||||||
|
void SetPatternSelector(PatternSelector* selector);
|
||||||
|
void SetChoiceModel(ChoiceModel* model);
|
||||||
|
void SetChoiceView(ChoiceView* view);
|
||||||
|
|
||||||
|
EditView* GetEditView() { return fEditView; }
|
||||||
|
PatternSelector* GetPatternSelector()
|
||||||
|
{ return fPatternSelector; }
|
||||||
|
ChoiceModel* GetChoiceModel() { return fChoiceModel; }
|
||||||
|
ChoiceView* GetChoiceView() { return fChoiceView; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
EditView* fEditView;
|
||||||
|
PatternSelector* fPatternSelector;
|
||||||
|
ChoiceModel* fChoiceModel;
|
||||||
|
ChoiceView* fChoiceView;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BAutoCompleter(
|
||||||
|
CompletionStyle* completionStyle = NULL);
|
||||||
|
BAutoCompleter(EditView* editView,
|
||||||
|
ChoiceModel* choiceModel,
|
||||||
|
ChoiceView* choiceView,
|
||||||
|
PatternSelector* patternSelector);
|
||||||
|
virtual ~BAutoCompleter();
|
||||||
|
|
||||||
|
void EditViewStateChanged(
|
||||||
|
bool updateChoices = true);
|
||||||
|
|
||||||
|
bool Select(int32 index);
|
||||||
|
bool SelectNext(bool wrap = false);
|
||||||
|
bool SelectPrevious(bool wrap = false);
|
||||||
|
bool IsChoiceSelected() const;
|
||||||
|
int32 CountChoices() const;
|
||||||
|
int32 CountVisibleChoices() const;
|
||||||
|
int32 SelectedChoiceIndex() const;
|
||||||
|
|
||||||
|
void ApplyChoice(bool hideChoices = true);
|
||||||
|
void CancelChoice();
|
||||||
|
|
||||||
|
void SetEditView(EditView* view);
|
||||||
|
void SetPatternSelector(PatternSelector* selector);
|
||||||
|
void SetChoiceModel(ChoiceModel* model);
|
||||||
|
void SetChoiceView(ChoiceView* view);
|
||||||
|
|
||||||
|
void SetCompletionStyle(CompletionStyle* style);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CompletionStyle* fCompletionStyle;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _AUTO_COMPLETER_H
|
||||||
@@ -0,0 +1,467 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Oliver Tappe <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AutoCompleterDefaultImpl.h"
|
||||||
|
|
||||||
|
#include <ListView.h>
|
||||||
|
#include <Screen.h>
|
||||||
|
#include <ScrollView.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDefaultPatternSelector
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultPatternSelector::SelectPatternBounds(const BString& text,
|
||||||
|
int32 caretPos, int32* start, int32* length)
|
||||||
|
{
|
||||||
|
if (!start || !length)
|
||||||
|
return;
|
||||||
|
*start = 0;
|
||||||
|
*length = text.Length();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDefaultCompletionStyle
|
||||||
|
|
||||||
|
|
||||||
|
BDefaultCompletionStyle::BDefaultCompletionStyle(
|
||||||
|
BAutoCompleter::EditView* editView,
|
||||||
|
BAutoCompleter::ChoiceModel* choiceModel,
|
||||||
|
BAutoCompleter::ChoiceView* choiceView,
|
||||||
|
BAutoCompleter::PatternSelector* patternSelector)
|
||||||
|
:
|
||||||
|
CompletionStyle(editView, choiceModel, choiceView, patternSelector),
|
||||||
|
fSelectedIndex(-1),
|
||||||
|
fPatternStartPos(0),
|
||||||
|
fPatternLength(0),
|
||||||
|
fIgnoreEditViewStateChanges(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BDefaultCompletionStyle::~BDefaultCompletionStyle()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDefaultCompletionStyle::Select(int32 index)
|
||||||
|
{
|
||||||
|
if (!fChoiceView || !fChoiceModel || index == fSelectedIndex
|
||||||
|
|| index < -1 || index >= fChoiceModel->CountChoices()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fSelectedIndex = index;
|
||||||
|
fChoiceView->SelectChoiceAt(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDefaultCompletionStyle::SelectNext(bool wrap)
|
||||||
|
{
|
||||||
|
if (!fChoiceModel || fChoiceModel->CountChoices() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int32 newIndex = fSelectedIndex + 1;
|
||||||
|
if (newIndex >= fChoiceModel->CountChoices()) {
|
||||||
|
if (wrap)
|
||||||
|
newIndex = 0;
|
||||||
|
else
|
||||||
|
newIndex = fSelectedIndex;
|
||||||
|
}
|
||||||
|
return Select(newIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDefaultCompletionStyle::SelectPrevious(bool wrap)
|
||||||
|
{
|
||||||
|
if (!fChoiceModel || fChoiceModel->CountChoices() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int32 newIndex = fSelectedIndex - 1;
|
||||||
|
if (newIndex < 0) {
|
||||||
|
if (wrap)
|
||||||
|
newIndex = fChoiceModel->CountChoices() - 1;
|
||||||
|
else
|
||||||
|
newIndex = 0;
|
||||||
|
}
|
||||||
|
return Select(newIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDefaultCompletionStyle::IsChoiceSelected() const
|
||||||
|
{
|
||||||
|
return fSelectedIndex >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BDefaultCompletionStyle::SelectedChoiceIndex() const
|
||||||
|
{
|
||||||
|
return fSelectedIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultCompletionStyle::ApplyChoice(bool hideChoices)
|
||||||
|
{
|
||||||
|
if (!fChoiceModel || !fChoiceView || !fEditView || fSelectedIndex < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BString completedText(fFullEnteredText);
|
||||||
|
completedText.Remove(fPatternStartPos, fPatternLength);
|
||||||
|
const BString& choiceStr = fChoiceModel->ChoiceAt(fSelectedIndex)->Text();
|
||||||
|
completedText.Insert(choiceStr, fPatternStartPos);
|
||||||
|
|
||||||
|
fIgnoreEditViewStateChanges = true;
|
||||||
|
|
||||||
|
fFullEnteredText = completedText;
|
||||||
|
fPatternLength = choiceStr.Length();
|
||||||
|
fEditView->SetEditViewState(completedText,
|
||||||
|
fPatternStartPos + choiceStr.Length());
|
||||||
|
|
||||||
|
if (hideChoices) {
|
||||||
|
fChoiceView->HideChoices();
|
||||||
|
Select(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fIgnoreEditViewStateChanges = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultCompletionStyle::CancelChoice()
|
||||||
|
{
|
||||||
|
if (!fChoiceView || !fEditView)
|
||||||
|
return;
|
||||||
|
if (fChoiceView->ChoicesAreShown()) {
|
||||||
|
fIgnoreEditViewStateChanges = true;
|
||||||
|
|
||||||
|
fEditView->SetEditViewState(fFullEnteredText,
|
||||||
|
fPatternStartPos + fPatternLength);
|
||||||
|
fChoiceView->HideChoices();
|
||||||
|
Select(-1);
|
||||||
|
|
||||||
|
fIgnoreEditViewStateChanges = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultCompletionStyle::EditViewStateChanged(bool updateChoices)
|
||||||
|
{
|
||||||
|
if (fIgnoreEditViewStateChanges || !fChoiceModel || !fChoiceView
|
||||||
|
|| !fEditView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString text;
|
||||||
|
int32 caretPos;
|
||||||
|
fEditView->GetEditViewState(text, &caretPos);
|
||||||
|
if (fFullEnteredText == text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fFullEnteredText = text;
|
||||||
|
|
||||||
|
if (!updateChoices)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fPatternSelector->SelectPatternBounds(text, caretPos, &fPatternStartPos,
|
||||||
|
&fPatternLength);
|
||||||
|
BString pattern(text.String() + fPatternStartPos, fPatternLength);
|
||||||
|
fChoiceModel->FetchChoicesFor(pattern);
|
||||||
|
|
||||||
|
Select(-1);
|
||||||
|
// show a single choice only if it doesn't match the pattern exactly:
|
||||||
|
if (fChoiceModel->CountChoices() > 1 || (fChoiceModel->CountChoices() == 1
|
||||||
|
&& pattern.ICompare(fChoiceModel->ChoiceAt(0)->Text())) != 0) {
|
||||||
|
fChoiceView->ShowChoices(this);
|
||||||
|
fChoiceView->SelectChoiceAt(fSelectedIndex);
|
||||||
|
} else
|
||||||
|
fChoiceView->HideChoices();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDefaultChoiceView::ListView
|
||||||
|
|
||||||
|
|
||||||
|
static const int32 MSG_INVOKED = 'invk';
|
||||||
|
|
||||||
|
|
||||||
|
BDefaultChoiceView::ListView::ListView(
|
||||||
|
BAutoCompleter::CompletionStyle* completer)
|
||||||
|
:
|
||||||
|
BListView(BRect(0, 0, 100, 100), "ChoiceViewList"),
|
||||||
|
fCompleter(completer)
|
||||||
|
{
|
||||||
|
// we need to check if user clicks outside of window-bounds:
|
||||||
|
SetEventMask(B_POINTER_EVENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::ListView::AttachedToWindow()
|
||||||
|
{
|
||||||
|
SetTarget(this);
|
||||||
|
SetInvocationMessage(new BMessage(MSG_INVOKED));
|
||||||
|
BListView::AttachedToWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::ListView::SelectionChanged()
|
||||||
|
{
|
||||||
|
fCompleter->Select(CurrentSelection(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::ListView::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch(message->what) {
|
||||||
|
case MSG_INVOKED:
|
||||||
|
fCompleter->ApplyChoice();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BListView::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::ListView::MouseDown(BPoint point)
|
||||||
|
{
|
||||||
|
if (!Window()->Frame().Contains(ConvertToScreen(point)))
|
||||||
|
// click outside of window, so we close it:
|
||||||
|
Window()->Quit();
|
||||||
|
else
|
||||||
|
BListView::MouseDown(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDefaultChoiceView::ListItem
|
||||||
|
|
||||||
|
|
||||||
|
BDefaultChoiceView::ListItem::ListItem(const BAutoCompleter::Choice* choice)
|
||||||
|
:
|
||||||
|
BListItem()
|
||||||
|
{
|
||||||
|
fPreText = choice->DisplayText();
|
||||||
|
if (choice->MatchLen() > 0) {
|
||||||
|
fPreText.MoveInto(fMatchText, choice->MatchPos(), choice->MatchLen());
|
||||||
|
fPreText.MoveInto(fPostText, choice->MatchPos(), fPreText.Length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::ListItem::DrawItem(BView* owner, BRect frame,
|
||||||
|
bool complete)
|
||||||
|
{
|
||||||
|
rgb_color textColor;
|
||||||
|
rgb_color nonMatchTextColor;
|
||||||
|
rgb_color backColor;
|
||||||
|
rgb_color matchColor;
|
||||||
|
if (IsSelected()) {
|
||||||
|
textColor = ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR);
|
||||||
|
backColor = ui_color(B_MENU_SELECTED_BACKGROUND_COLOR);
|
||||||
|
} else {
|
||||||
|
textColor = ui_color(B_DOCUMENT_TEXT_COLOR);
|
||||||
|
backColor = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
|
||||||
|
}
|
||||||
|
matchColor = tint_color(backColor, (B_NO_TINT + B_DARKEN_1_TINT) / 2);
|
||||||
|
nonMatchTextColor = tint_color(backColor, 1.7);
|
||||||
|
|
||||||
|
BFont font;
|
||||||
|
font_height fontHeight;
|
||||||
|
owner->GetFont(&font);
|
||||||
|
font.GetHeight(&fontHeight);
|
||||||
|
float xPos = frame.left + 1;
|
||||||
|
float yPos = frame.top + fontHeight.ascent;
|
||||||
|
float w;
|
||||||
|
if (fPreText.Length()) {
|
||||||
|
w = owner->StringWidth(fPreText.String());
|
||||||
|
owner->SetLowColor(backColor);
|
||||||
|
owner->FillRect(BRect(xPos, frame.top, xPos + w - 1, frame.bottom),
|
||||||
|
B_SOLID_LOW);
|
||||||
|
owner->SetHighColor(nonMatchTextColor);
|
||||||
|
owner->DrawString(fPreText.String(), BPoint(xPos, yPos));
|
||||||
|
xPos += w;
|
||||||
|
}
|
||||||
|
if (fMatchText.Length()) {
|
||||||
|
w = owner->StringWidth(fMatchText.String());
|
||||||
|
owner->SetLowColor(matchColor);
|
||||||
|
owner->FillRect(BRect(xPos, frame.top, xPos + w - 1, frame.bottom),
|
||||||
|
B_SOLID_LOW);
|
||||||
|
owner->SetHighColor(textColor);
|
||||||
|
owner->DrawString(fMatchText.String(), BPoint(xPos, yPos));
|
||||||
|
xPos += w;
|
||||||
|
}
|
||||||
|
if (fPostText.Length()) {
|
||||||
|
w = owner->StringWidth(fPostText.String());
|
||||||
|
owner->SetLowColor(backColor);
|
||||||
|
owner->FillRect(BRect(xPos, frame.top, xPos + w - 1, frame.bottom),
|
||||||
|
B_SOLID_LOW);
|
||||||
|
owner->SetHighColor(nonMatchTextColor);
|
||||||
|
owner->DrawString(fPostText.String(), BPoint(xPos, yPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - BDefaultChoiceView
|
||||||
|
|
||||||
|
|
||||||
|
BDefaultChoiceView::BDefaultChoiceView()
|
||||||
|
:
|
||||||
|
fWindow(NULL),
|
||||||
|
fListView(NULL),
|
||||||
|
fMaxVisibleChoices(8)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BDefaultChoiceView::~BDefaultChoiceView()
|
||||||
|
{
|
||||||
|
HideChoices();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::SelectChoiceAt(int32 index)
|
||||||
|
{
|
||||||
|
if (fListView && fListView->LockLooper()) {
|
||||||
|
if (index < 0)
|
||||||
|
fListView->DeselectAll();
|
||||||
|
else {
|
||||||
|
fListView->Select(index);
|
||||||
|
fListView->ScrollToSelection();
|
||||||
|
}
|
||||||
|
fListView->UnlockLooper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::ShowChoices(BAutoCompleter::CompletionStyle* completer)
|
||||||
|
{
|
||||||
|
if (!completer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HideChoices();
|
||||||
|
|
||||||
|
BAutoCompleter::ChoiceModel* choiceModel = completer->GetChoiceModel();
|
||||||
|
BAutoCompleter::EditView* editView = completer->GetEditView();
|
||||||
|
|
||||||
|
if (!editView || !choiceModel || choiceModel->CountChoices() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fListView = new ListView(completer);
|
||||||
|
int32 count = choiceModel->CountChoices();
|
||||||
|
for(int32 i = 0; i<count; ++i) {
|
||||||
|
fListView->AddItem(
|
||||||
|
new ListItem(choiceModel->ChoiceAt(i))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BScrollView *scrollView = NULL;
|
||||||
|
if (count > fMaxVisibleChoices) {
|
||||||
|
scrollView = new BScrollView("", fListView, B_FOLLOW_NONE, 0, false, true, B_NO_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
fWindow = new BWindow(BRect(0, 0, 100, 100), "", B_BORDERED_WINDOW_LOOK,
|
||||||
|
B_NORMAL_WINDOW_FEEL, B_NOT_MOVABLE | B_WILL_ACCEPT_FIRST_CLICK
|
||||||
|
| B_AVOID_FOCUS | B_ASYNCHRONOUS_CONTROLS);
|
||||||
|
if (scrollView != NULL)
|
||||||
|
fWindow->AddChild(scrollView);
|
||||||
|
else
|
||||||
|
fWindow->AddChild(fListView);
|
||||||
|
|
||||||
|
int32 visibleCount = min_c(count, fMaxVisibleChoices);
|
||||||
|
float listHeight = fListView->ItemFrame(visibleCount - 1).bottom + 1;
|
||||||
|
|
||||||
|
BRect pvRect = editView->GetAdjustmentFrame();
|
||||||
|
BRect listRect = pvRect;
|
||||||
|
listRect.bottom = listRect.top + listHeight - 1;
|
||||||
|
BRect screenRect = BScreen().Frame();
|
||||||
|
if (listRect.bottom + 1 + listHeight <= screenRect.bottom)
|
||||||
|
listRect.OffsetTo(pvRect.left, pvRect.bottom + 1);
|
||||||
|
else
|
||||||
|
listRect.OffsetTo(pvRect.left, pvRect.top - listHeight);
|
||||||
|
|
||||||
|
if (scrollView != NULL) {
|
||||||
|
// Moving here to cut off the scrollbar top
|
||||||
|
scrollView->MoveTo(0, -1);
|
||||||
|
// Adding the 1 and 2 to cut-off the scroll-bar top, right and bottom
|
||||||
|
scrollView->ResizeTo(listRect.Width() + 1, listRect.Height() + 2);
|
||||||
|
// Move here to compensate for the above
|
||||||
|
fListView->MoveTo(0, 1);
|
||||||
|
fListView->ResizeTo(listRect.Width() - B_V_SCROLL_BAR_WIDTH, listRect.Height());
|
||||||
|
} else {
|
||||||
|
fListView->MoveTo(0, 0);
|
||||||
|
fListView->ResizeTo(listRect.Width(), listRect.Height());
|
||||||
|
}
|
||||||
|
fWindow->MoveTo(listRect.left, listRect.top);
|
||||||
|
fWindow->ResizeTo(listRect.Width(), listRect.Height());
|
||||||
|
fWindow->Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::HideChoices()
|
||||||
|
{
|
||||||
|
if (fWindow && fWindow->Lock()) {
|
||||||
|
fWindow->Quit();
|
||||||
|
fWindow = NULL;
|
||||||
|
fListView = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDefaultChoiceView::ChoicesAreShown()
|
||||||
|
{
|
||||||
|
return (fWindow != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BDefaultChoiceView::CountVisibleChoices() const
|
||||||
|
{
|
||||||
|
if (fListView)
|
||||||
|
return min_c(fMaxVisibleChoices, fListView->CountItems());
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BDefaultChoiceView::SetMaxVisibleChoices(int32 choices)
|
||||||
|
{
|
||||||
|
if (choices < 1)
|
||||||
|
choices = 1;
|
||||||
|
if (choices == fMaxVisibleChoices)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fMaxVisibleChoices = choices;
|
||||||
|
|
||||||
|
// TODO: Update live?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BDefaultChoiceView::MaxVisibleChoices() const
|
||||||
|
{
|
||||||
|
return fMaxVisibleChoices;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Oliver Tappe <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef _AUTO_COMPLETER_DEFAULT_IMPL_H
|
||||||
|
#define _AUTO_COMPLETER_DEFAULT_IMPL_H
|
||||||
|
|
||||||
|
#include <ListView.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "AutoCompleter.h"
|
||||||
|
|
||||||
|
class BDefaultPatternSelector : public BAutoCompleter::PatternSelector {
|
||||||
|
public:
|
||||||
|
virtual void SelectPatternBounds(const BString& text,
|
||||||
|
int32 caretPos, int32* start,
|
||||||
|
int32* length);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BDefaultCompletionStyle : public BAutoCompleter::CompletionStyle {
|
||||||
|
public:
|
||||||
|
BDefaultCompletionStyle(
|
||||||
|
BAutoCompleter::EditView* editView,
|
||||||
|
BAutoCompleter::ChoiceModel* choiceModel,
|
||||||
|
BAutoCompleter::ChoiceView* choiceView,
|
||||||
|
BAutoCompleter::PatternSelector*
|
||||||
|
patternSelector);
|
||||||
|
virtual ~BDefaultCompletionStyle();
|
||||||
|
|
||||||
|
virtual bool Select(int32 index);
|
||||||
|
virtual bool SelectNext(bool wrap = false);
|
||||||
|
virtual bool SelectPrevious(bool wrap = false);
|
||||||
|
virtual bool IsChoiceSelected() const;
|
||||||
|
virtual int32 SelectedChoiceIndex() const;
|
||||||
|
|
||||||
|
virtual void ApplyChoice(bool hideChoices = true);
|
||||||
|
virtual void CancelChoice();
|
||||||
|
|
||||||
|
virtual void EditViewStateChanged(bool updateChoices);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BString fFullEnteredText;
|
||||||
|
int32 fSelectedIndex;
|
||||||
|
int32 fPatternStartPos;
|
||||||
|
int32 fPatternLength;
|
||||||
|
bool fIgnoreEditViewStateChanges;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BDefaultChoiceView : public BAutoCompleter::ChoiceView {
|
||||||
|
protected:
|
||||||
|
class ListView : public BListView {
|
||||||
|
public:
|
||||||
|
ListView(
|
||||||
|
BAutoCompleter::CompletionStyle* completer);
|
||||||
|
virtual void SelectionChanged();
|
||||||
|
virtual void MessageReceived(BMessage* msg);
|
||||||
|
virtual void MouseDown(BPoint point);
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BAutoCompleter::CompletionStyle* fCompleter;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ListItem : public BListItem {
|
||||||
|
public:
|
||||||
|
ListItem(const BAutoCompleter::Choice* choice);
|
||||||
|
virtual void DrawItem(BView* owner, BRect frame,
|
||||||
|
bool complete = false);
|
||||||
|
private:
|
||||||
|
BString fPreText;
|
||||||
|
BString fMatchText;
|
||||||
|
BString fPostText;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
BDefaultChoiceView();
|
||||||
|
virtual ~BDefaultChoiceView();
|
||||||
|
|
||||||
|
virtual void SelectChoiceAt(int32 index);
|
||||||
|
virtual void ShowChoices(
|
||||||
|
BAutoCompleter::CompletionStyle* completer);
|
||||||
|
virtual void HideChoices();
|
||||||
|
virtual bool ChoicesAreShown();
|
||||||
|
virtual int32 CountVisibleChoices() const;
|
||||||
|
|
||||||
|
void SetMaxVisibleChoices(int32 choices);
|
||||||
|
int32 MaxVisibleChoices() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BWindow* fWindow;
|
||||||
|
ListView* fListView;
|
||||||
|
int32 fMaxVisibleChoices;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _AUTO_COMPLETER_DEFAULT_IMPL_H
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Oliver Tappe <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TextViewCompleter.h"
|
||||||
|
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <TextControl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "AutoCompleterDefaultImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TextViewWrapper
|
||||||
|
|
||||||
|
|
||||||
|
TextViewCompleter::TextViewWrapper::TextViewWrapper(BTextView* textView)
|
||||||
|
:
|
||||||
|
fTextView(textView)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextViewCompleter::TextViewWrapper::GetEditViewState(BString& text,
|
||||||
|
int32* caretPos)
|
||||||
|
{
|
||||||
|
if (fTextView && fTextView->LockLooper()) {
|
||||||
|
text = fTextView->Text();
|
||||||
|
if (caretPos) {
|
||||||
|
int32 end;
|
||||||
|
fTextView->GetSelection(caretPos, &end);
|
||||||
|
}
|
||||||
|
fTextView->UnlockLooper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextViewCompleter::TextViewWrapper::SetEditViewState(const BString& text,
|
||||||
|
int32 caretPos, int32 selectionLength)
|
||||||
|
{
|
||||||
|
if (fTextView && fTextView->LockLooper()) {
|
||||||
|
fTextView->SetText(text.String(), text.Length());
|
||||||
|
fTextView->Select(caretPos, caretPos + selectionLength);
|
||||||
|
fTextView->ScrollToSelection();
|
||||||
|
fTextView->UnlockLooper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
TextViewCompleter::TextViewWrapper::GetAdjustmentFrame()
|
||||||
|
{
|
||||||
|
BRect frame = fTextView->Bounds();
|
||||||
|
frame = fTextView->ConvertToScreen(frame);
|
||||||
|
frame.InsetBy(0, -3);
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
TextViewCompleter::TextViewCompleter(BTextView* textView, ChoiceModel* model,
|
||||||
|
PatternSelector* patternSelector)
|
||||||
|
:
|
||||||
|
BAutoCompleter(new TextViewWrapper(textView), model,
|
||||||
|
new BDefaultChoiceView(), patternSelector),
|
||||||
|
BMessageFilter(B_KEY_DOWN),
|
||||||
|
fTextView(textView),
|
||||||
|
fModificationsReported(false)
|
||||||
|
{
|
||||||
|
fTextView->AddFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextViewCompleter::~TextViewCompleter()
|
||||||
|
{
|
||||||
|
fTextView->RemoveFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextViewCompleter::SetModificationsReported(bool reported)
|
||||||
|
{
|
||||||
|
fModificationsReported = reported;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TextViewCompleter::TextModified(bool updateChoices)
|
||||||
|
{
|
||||||
|
EditViewStateChanged(updateChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
filter_result
|
||||||
|
TextViewCompleter::Filter(BMessage* message, BHandler** target)
|
||||||
|
{
|
||||||
|
const char* bytes;
|
||||||
|
int32 modifiers;
|
||||||
|
if ((!target || message->FindString("bytes", &bytes) != B_OK
|
||||||
|
|| message->FindInt32("modifiers", &modifiers) != B_OK)
|
||||||
|
|| (modifiers & (B_CONTROL_KEY | B_COMMAND_KEY | B_OPTION_KEY
|
||||||
|
| B_SHIFT_KEY)) != 0) {
|
||||||
|
return B_DISPATCH_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bytes[0]) {
|
||||||
|
case B_UP_ARROW:
|
||||||
|
SelectPrevious();
|
||||||
|
// Insert the current choice into the text view, so the user can
|
||||||
|
// continue typing. This will not trigger another evaluation, since
|
||||||
|
// we don't invoke EditViewStateChanged().
|
||||||
|
ApplyChoice(false);
|
||||||
|
return B_SKIP_MESSAGE;
|
||||||
|
case B_DOWN_ARROW:
|
||||||
|
SelectNext();
|
||||||
|
// See above.
|
||||||
|
ApplyChoice(false);
|
||||||
|
return B_SKIP_MESSAGE;
|
||||||
|
case B_PAGE_UP:
|
||||||
|
{
|
||||||
|
int32 index = SelectedChoiceIndex() - CountVisibleChoices();
|
||||||
|
index = max_c(index, 0);
|
||||||
|
Select(index);
|
||||||
|
ApplyChoice(false);
|
||||||
|
return B_SKIP_MESSAGE;
|
||||||
|
}
|
||||||
|
case B_PAGE_DOWN:
|
||||||
|
{
|
||||||
|
int32 index = SelectedChoiceIndex() + CountVisibleChoices();
|
||||||
|
index = min_c(index, CountChoices() - 1);
|
||||||
|
Select(index);
|
||||||
|
ApplyChoice(false);
|
||||||
|
return B_SKIP_MESSAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_ESCAPE:
|
||||||
|
CancelChoice();
|
||||||
|
return B_DISPATCH_MESSAGE;
|
||||||
|
case B_RETURN:
|
||||||
|
if (IsChoiceSelected()) {
|
||||||
|
ApplyChoice();
|
||||||
|
EditViewStateChanged();
|
||||||
|
} else
|
||||||
|
CancelChoice();
|
||||||
|
return B_DISPATCH_MESSAGE;
|
||||||
|
case B_TAB: {
|
||||||
|
// make sure that the choices-view is closed when tabbing out:
|
||||||
|
CancelChoice();
|
||||||
|
return B_DISPATCH_MESSAGE;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
if (!fModificationsReported) {
|
||||||
|
// dispatch message to textview manually...
|
||||||
|
Looper()->DispatchMessage(message, *target);
|
||||||
|
// ...and propagate the new state to the auto-completer:
|
||||||
|
EditViewStateChanged();
|
||||||
|
return B_SKIP_MESSAGE;
|
||||||
|
}
|
||||||
|
return B_DISPATCH_MESSAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Oliver Tappe <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef TEXT_CONTROL_COMPLETER_H
|
||||||
|
#define TEXT_CONTROL_COMPLETER_H
|
||||||
|
|
||||||
|
#include <MessageFilter.h>
|
||||||
|
|
||||||
|
#include "AutoCompleter.h"
|
||||||
|
|
||||||
|
|
||||||
|
class BTextView;
|
||||||
|
|
||||||
|
class TextViewCompleter : protected BAutoCompleter, public BMessageFilter {
|
||||||
|
public:
|
||||||
|
TextViewCompleter(BTextView* textView,
|
||||||
|
ChoiceModel* choiceModel = NULL,
|
||||||
|
PatternSelector* patternSelector = NULL);
|
||||||
|
virtual ~TextViewCompleter();
|
||||||
|
|
||||||
|
void SetModificationsReported(bool reported);
|
||||||
|
void TextModified(bool updateChoices);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual filter_result Filter(BMessage* message, BHandler** target);
|
||||||
|
|
||||||
|
class TextViewWrapper : public EditView {
|
||||||
|
public:
|
||||||
|
TextViewWrapper(BTextView* textView);
|
||||||
|
virtual BRect GetAdjustmentFrame();
|
||||||
|
virtual void GetEditViewState(BString& text,
|
||||||
|
int32* caretPos);
|
||||||
|
virtual void SetEditViewState(const BString& text,
|
||||||
|
int32 caretPos, int32 selectionLength = 0);
|
||||||
|
private:
|
||||||
|
BTextView* fTextView;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
BTextView* fTextView;
|
||||||
|
bool fModificationsReported;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TEXT_CONTROL_COMPLETER_H
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005-2007, Ingo Weinhold, [email protected].
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _AUTO_LOCKER_H
|
||||||
|
#define _AUTO_LOCKER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
// AutoLockerStandardLocking
|
||||||
|
template<typename Lockable>
|
||||||
|
class AutoLockerStandardLocking {
|
||||||
|
public:
|
||||||
|
inline bool Lock(Lockable* lockable)
|
||||||
|
{
|
||||||
|
return lockable->Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock(Lockable* lockable)
|
||||||
|
{
|
||||||
|
lockable->Unlock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// AutoLockerReadLocking
|
||||||
|
template<typename Lockable>
|
||||||
|
class AutoLockerReadLocking {
|
||||||
|
public:
|
||||||
|
inline bool Lock(Lockable* lockable)
|
||||||
|
{
|
||||||
|
return lockable->ReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock(Lockable* lockable)
|
||||||
|
{
|
||||||
|
lockable->ReadUnlock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// AutoLockerWriteLocking
|
||||||
|
template<typename Lockable>
|
||||||
|
class AutoLockerWriteLocking {
|
||||||
|
public:
|
||||||
|
inline bool Lock(Lockable* lockable)
|
||||||
|
{
|
||||||
|
return lockable->WriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock(Lockable* lockable)
|
||||||
|
{
|
||||||
|
lockable->WriteUnlock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// AutoLocker
|
||||||
|
template<typename Lockable,
|
||||||
|
typename Locking = AutoLockerStandardLocking<Lockable> >
|
||||||
|
class AutoLocker {
|
||||||
|
private:
|
||||||
|
typedef AutoLocker<Lockable, Locking> ThisClass;
|
||||||
|
public:
|
||||||
|
inline AutoLocker()
|
||||||
|
:
|
||||||
|
fLockable(NULL),
|
||||||
|
fLocked(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AutoLocker(const Locking& locking)
|
||||||
|
:
|
||||||
|
fLockable(NULL),
|
||||||
|
fLocking(locking),
|
||||||
|
fLocked(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AutoLocker(Lockable* lockable, bool alreadyLocked = false,
|
||||||
|
bool lockIfNotLocked = true)
|
||||||
|
:
|
||||||
|
fLockable(lockable),
|
||||||
|
fLocked(fLockable && alreadyLocked)
|
||||||
|
{
|
||||||
|
if (!alreadyLocked && lockIfNotLocked)
|
||||||
|
Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AutoLocker(Lockable& lockable, bool alreadyLocked = false,
|
||||||
|
bool lockIfNotLocked = true)
|
||||||
|
:
|
||||||
|
fLockable(&lockable),
|
||||||
|
fLocked(fLockable && alreadyLocked)
|
||||||
|
{
|
||||||
|
if (!alreadyLocked && lockIfNotLocked)
|
||||||
|
Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~AutoLocker()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetTo(Lockable* lockable, bool alreadyLocked,
|
||||||
|
bool lockIfNotLocked = true)
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
fLockable = lockable;
|
||||||
|
fLocked = (lockable && alreadyLocked);
|
||||||
|
if (!alreadyLocked && lockIfNotLocked)
|
||||||
|
Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetTo(Lockable& lockable, bool alreadyLocked,
|
||||||
|
bool lockIfNotLocked = true)
|
||||||
|
{
|
||||||
|
SetTo(&lockable, alreadyLocked, lockIfNotLocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unset()
|
||||||
|
{
|
||||||
|
Unlock();
|
||||||
|
Detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool Lock()
|
||||||
|
{
|
||||||
|
if (fLockable && !fLocked)
|
||||||
|
fLocked = fLocking.Lock(fLockable);
|
||||||
|
return fLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Unlock()
|
||||||
|
{
|
||||||
|
if (fLockable && fLocked) {
|
||||||
|
fLocking.Unlock(fLockable);
|
||||||
|
fLocked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Detach()
|
||||||
|
{
|
||||||
|
fLockable = NULL;
|
||||||
|
fLocked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AutoLocker<Lockable, Locking>& operator=(Lockable* lockable)
|
||||||
|
{
|
||||||
|
SetTo(lockable);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline AutoLocker<Lockable, Locking>& operator=(Lockable& lockable)
|
||||||
|
{
|
||||||
|
SetTo(&lockable);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool IsLocked() const { return fLocked; }
|
||||||
|
|
||||||
|
inline operator bool() const { return fLocked; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Lockable* fLockable;
|
||||||
|
Locking fLocking;
|
||||||
|
bool fLocked;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using BPrivate::AutoLocker;
|
||||||
|
using BPrivate::AutoLockerReadLocking;
|
||||||
|
using BPrivate::AutoLockerWriteLocking;
|
||||||
|
|
||||||
|
#endif // _AUTO_LOCKER_H
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Stephan Aßmus <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BaseURL.h"
|
||||||
|
|
||||||
|
|
||||||
|
BString
|
||||||
|
baseURL(const BString string)
|
||||||
|
{
|
||||||
|
int32 baseURLStart = string.FindFirst("://") + 3;
|
||||||
|
int32 baseURLEnd = string.FindFirst("/", baseURLStart + 1);
|
||||||
|
BString result;
|
||||||
|
result.SetTo(string.String() + baseURLStart, baseURLEnd - baseURLStart);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Stephan Aßmus <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef BASE_URL_H
|
||||||
|
#define BASE_URL_H
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
BString baseURL(const BString string);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BASE_URL_H
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Stephan Aßmus <[email protected]>. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BitmapButton.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <TranslationUtils.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const float kFrameInset = 2;
|
||||||
|
|
||||||
|
|
||||||
|
BitmapButton::BitmapButton(const char* resourceName, BMessage* message)
|
||||||
|
:
|
||||||
|
BButton("", message),
|
||||||
|
fBitmap(BTranslationUtils::GetBitmap(resourceName)),
|
||||||
|
fBackgroundMode(BUTTON_BACKGROUND)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BitmapButton::BitmapButton(const uint8* bits, uint32 width, uint32 height,
|
||||||
|
color_space format, BMessage* message)
|
||||||
|
:
|
||||||
|
BButton("", message),
|
||||||
|
fBitmap(new BBitmap(BRect(0, 0, width - 1, height - 1), 0, format)),
|
||||||
|
fBackgroundMode(BUTTON_BACKGROUND)
|
||||||
|
{
|
||||||
|
memcpy(fBitmap->Bits(), bits, fBitmap->BitsLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BitmapButton::~BitmapButton()
|
||||||
|
{
|
||||||
|
delete fBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
BitmapButton::MinSize()
|
||||||
|
{
|
||||||
|
BSize min(0, 0);
|
||||||
|
if (fBitmap) {
|
||||||
|
min.width = fBitmap->Bounds().Width();
|
||||||
|
min.height = fBitmap->Bounds().Height();
|
||||||
|
}
|
||||||
|
min.width += kFrameInset * 2;
|
||||||
|
min.height += kFrameInset * 2;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
BitmapButton::MaxSize()
|
||||||
|
{
|
||||||
|
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
BitmapButton::PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BitmapButton::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect bounds(Bounds());
|
||||||
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
uint32 flags = be_control_look->Flags(this);
|
||||||
|
|
||||||
|
if (fBackgroundMode == BUTTON_BACKGROUND || Value() == B_CONTROL_ON) {
|
||||||
|
be_control_look->DrawButtonBackground(this, bounds, updateRect, base,
|
||||||
|
flags);
|
||||||
|
} else {
|
||||||
|
SetHighColor(tint_color(base, B_DARKEN_2_TINT));
|
||||||
|
StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
|
||||||
|
bounds.bottom--;
|
||||||
|
be_control_look->DrawMenuBarBackground(this, bounds, updateRect, base,
|
||||||
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fBitmap == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SetDrawingMode(B_OP_ALPHA);
|
||||||
|
|
||||||
|
if (!IsEnabled()) {
|
||||||
|
SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
SetHighColor(0, 0, 0, 120);
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect bitmapBounds(fBitmap->Bounds());
|
||||||
|
BPoint bitmapLocation(
|
||||||
|
floorf((bounds.left + bounds.right
|
||||||
|
- (bitmapBounds.left + bitmapBounds.right)) / 2 + 0.5f),
|
||||||
|
floorf((bounds.top + bounds.bottom
|
||||||
|
- (bitmapBounds.top + bitmapBounds.bottom)) / 2 + 0.5f));
|
||||||
|
|
||||||
|
DrawBitmap(fBitmap, bitmapLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BitmapButton::SetBackgroundMode(uint32 mode)
|
||||||
|
{
|
||||||
|
if (fBackgroundMode != mode) {
|
||||||
|
fBackgroundMode = mode;
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Stephan Aßmus <[email protected]>. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef BITMAP_BUTTON_H
|
||||||
|
#define BITMAP_BUTTON_H
|
||||||
|
|
||||||
|
#include <Button.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BBitmap;
|
||||||
|
|
||||||
|
|
||||||
|
class BitmapButton : public BButton {
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
BUTTON_BACKGROUND = 0,
|
||||||
|
MENUBAR_BACKGROUND,
|
||||||
|
};
|
||||||
|
|
||||||
|
BitmapButton(const char* resourceName,
|
||||||
|
BMessage* message);
|
||||||
|
|
||||||
|
BitmapButton(const uint8* bits, uint32 width,
|
||||||
|
uint32 height, color_space format,
|
||||||
|
BMessage* message);
|
||||||
|
|
||||||
|
virtual ~BitmapButton();
|
||||||
|
|
||||||
|
virtual BSize MinSize();
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
virtual BSize PreferredSize();
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
|
||||||
|
void SetBackgroundMode(uint32 mode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
BBitmap* fBitmap;
|
||||||
|
uint32 fBackgroundMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BITMAP_BUTTON_H
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007-2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _DATE_TIME_H_
|
||||||
|
#define _DATE_TIME_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BMessage;
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
enum time_type {
|
||||||
|
B_GMT_TIME,
|
||||||
|
B_LOCAL_TIME
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum diff_type {
|
||||||
|
B_HOURS_DIFF,
|
||||||
|
B_MINUTES_DIFF,
|
||||||
|
B_SECONDS_DIFF,
|
||||||
|
B_MILLISECONDS_DIFF,
|
||||||
|
B_MICROSECONDS_DIFF
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BTime {
|
||||||
|
public:
|
||||||
|
BTime();
|
||||||
|
BTime(const BTime& other);
|
||||||
|
BTime(int32 hour, int32 minute, int32 second,
|
||||||
|
int32 microsecond = 0);
|
||||||
|
BTime(const BMessage* archive);
|
||||||
|
~BTime();
|
||||||
|
|
||||||
|
status_t Archive(BMessage* into) const;
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
bool IsValid(const BTime& time) const;
|
||||||
|
bool IsValid(int32 hour, int32 minute, int32 second,
|
||||||
|
int32 microsecond = 0) const;
|
||||||
|
|
||||||
|
static BTime CurrentTime(time_type type);
|
||||||
|
|
||||||
|
BTime Time() const;
|
||||||
|
bool SetTime(const BTime& time);
|
||||||
|
bool SetTime(int32 hour, int32 minute, int32 second,
|
||||||
|
int32 microsecond = 0);
|
||||||
|
|
||||||
|
BTime& AddHours(int32 hours);
|
||||||
|
BTime& AddMinutes(int32 minutes);
|
||||||
|
BTime& AddSeconds(int32 seconds);
|
||||||
|
BTime& AddMilliseconds(int32 milliseconds);
|
||||||
|
BTime& AddMicroseconds(int32 microseconds);
|
||||||
|
|
||||||
|
int32 Hour() const;
|
||||||
|
int32 Minute() const;
|
||||||
|
int32 Second() const;
|
||||||
|
int32 Millisecond() const;
|
||||||
|
int32 Microsecond() const;
|
||||||
|
bigtime_t Difference(const BTime& time,
|
||||||
|
diff_type type) const;
|
||||||
|
|
||||||
|
bool operator!=(const BTime& time) const;
|
||||||
|
bool operator==(const BTime& time) const;
|
||||||
|
|
||||||
|
bool operator<(const BTime& time) const;
|
||||||
|
bool operator<=(const BTime& time) const;
|
||||||
|
|
||||||
|
bool operator>(const BTime& time) const;
|
||||||
|
bool operator>=(const BTime& time) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bigtime_t _Microseconds() const;
|
||||||
|
BTime& _AddMicroseconds(bigtime_t microseconds);
|
||||||
|
bool _SetTime(bigtime_t hour, bigtime_t minute,
|
||||||
|
bigtime_t second, bigtime_t microsecond);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bigtime_t fMicroseconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BDate {
|
||||||
|
public:
|
||||||
|
BDate();
|
||||||
|
BDate(const BDate& other);
|
||||||
|
BDate(int32 year, int32 month, int32 day);
|
||||||
|
BDate(const BMessage* archive);
|
||||||
|
~BDate();
|
||||||
|
|
||||||
|
status_t Archive(BMessage* into) const;
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
bool IsValid(const BDate& date) const;
|
||||||
|
bool IsValid(int32 year, int32 month,
|
||||||
|
int32 day) const;
|
||||||
|
|
||||||
|
static BDate CurrentDate(time_type type);
|
||||||
|
|
||||||
|
BDate Date() const;
|
||||||
|
bool SetDate(const BDate& date);
|
||||||
|
|
||||||
|
bool SetDate(int32 year, int32 month, int32 day);
|
||||||
|
void GetDate(int32* year, int32* month, int32* day);
|
||||||
|
|
||||||
|
void AddDays(int32 days);
|
||||||
|
void AddYears(int32 years);
|
||||||
|
void AddMonths(int32 months);
|
||||||
|
|
||||||
|
int32 Day() const;
|
||||||
|
int32 Year() const;
|
||||||
|
int32 Month() const;
|
||||||
|
int32 Difference(const BDate& date) const;
|
||||||
|
|
||||||
|
int32 DayOfWeek() const;
|
||||||
|
int32 DayOfYear() const;
|
||||||
|
|
||||||
|
int32 WeekNumber() const;
|
||||||
|
bool IsLeapYear(int32 year) const;
|
||||||
|
|
||||||
|
int32 DaysInYear() const;
|
||||||
|
int32 DaysInMonth() const;
|
||||||
|
|
||||||
|
BString ShortDayName() const;
|
||||||
|
static BString ShortDayName(int32 day);
|
||||||
|
|
||||||
|
BString ShortMonthName() const;
|
||||||
|
static BString ShortMonthName(int32 month);
|
||||||
|
|
||||||
|
BString LongDayName() const;
|
||||||
|
static BString LongDayName(int32 day);
|
||||||
|
|
||||||
|
BString LongMonthName() const;
|
||||||
|
static BString LongMonthName(int32 month);
|
||||||
|
|
||||||
|
int32 DateToJulianDay() const;
|
||||||
|
static BDate JulianDayToDate(int32 julianDay);
|
||||||
|
|
||||||
|
bool operator!=(const BDate& date) const;
|
||||||
|
bool operator==(const BDate& date) const;
|
||||||
|
|
||||||
|
bool operator<(const BDate& date) const;
|
||||||
|
bool operator<=(const BDate& date) const;
|
||||||
|
|
||||||
|
bool operator>(const BDate& date) const;
|
||||||
|
bool operator>=(const BDate& date) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 _DaysInMonth(int32 year, int32 month) const;
|
||||||
|
bool _SetDate(int32 year, int32 month, int32 day);
|
||||||
|
int32 _DateToJulianDay(int32 year, int32 month,
|
||||||
|
int32 day) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 fDay;
|
||||||
|
int32 fYear;
|
||||||
|
int32 fMonth;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BDateTime {
|
||||||
|
public:
|
||||||
|
BDateTime();
|
||||||
|
BDateTime(const BDate &date, const BTime &time);
|
||||||
|
BDateTime(const BMessage* archive);
|
||||||
|
~BDateTime();
|
||||||
|
|
||||||
|
status_t Archive(BMessage* into) const;
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
|
||||||
|
static BDateTime CurrentDateTime(time_type type);
|
||||||
|
void SetDateTime(const BDate &date, const BTime &time);
|
||||||
|
|
||||||
|
BDate& Date();
|
||||||
|
const BDate& Date() const;
|
||||||
|
void SetDate(const BDate &date);
|
||||||
|
|
||||||
|
BTime& Time();
|
||||||
|
const BTime& Time() const;
|
||||||
|
void SetTime(const BTime &time);
|
||||||
|
|
||||||
|
int32 Time_t() const;
|
||||||
|
void SetTime_t(uint32 seconds);
|
||||||
|
|
||||||
|
bool operator!=(const BDateTime& dateTime) const;
|
||||||
|
bool operator==(const BDateTime& dateTime) const;
|
||||||
|
|
||||||
|
bool operator<(const BDateTime& dateTime) const;
|
||||||
|
bool operator<=(const BDateTime& dateTime) const;
|
||||||
|
|
||||||
|
bool operator>(const BDateTime& dateTime) const;
|
||||||
|
bool operator>=(const BDateTime& dateTime) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BDate fDate;
|
||||||
|
BTime fTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::time_type;
|
||||||
|
using BPrivate::B_GMT_TIME;
|
||||||
|
using BPrivate::B_LOCAL_TIME;
|
||||||
|
using BPrivate::diff_type;
|
||||||
|
using BPrivate::B_HOURS_DIFF;
|
||||||
|
using BPrivate::B_MINUTES_DIFF;
|
||||||
|
using BPrivate::B_SECONDS_DIFF;
|
||||||
|
using BPrivate::B_MILLISECONDS_DIFF;
|
||||||
|
using BPrivate::B_MICROSECONDS_DIFF;
|
||||||
|
using BPrivate::BTime;
|
||||||
|
using BPrivate::BDate;
|
||||||
|
using BPrivate::BDateTime;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _DATE_TIME_H_
|
||||||
@@ -0,0 +1,527 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2001-2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark Hogben
|
||||||
|
* DarkWyrm <[email protected]>
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
* Philippe Saint-Pierre, [email protected]
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FontSelectionView.h"
|
||||||
|
|
||||||
|
#include <Box.h>
|
||||||
|
#include <Catalog.h>
|
||||||
|
#include <Locale.h>
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <MenuField.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include <StringView.h>
|
||||||
|
#include <LayoutItem.h>
|
||||||
|
#include <GroupLayoutBuilder.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#undef B_TRANSLATION_CONTEXT
|
||||||
|
#define B_TRANSLATION_CONTEXT "Font Selection view"
|
||||||
|
|
||||||
|
|
||||||
|
static const float kMinSize = 8.0;
|
||||||
|
static const float kMaxSize = 18.0;
|
||||||
|
|
||||||
|
static const int32 kMsgSetFamily = 'fmly';
|
||||||
|
static const int32 kMsgSetStyle = 'styl';
|
||||||
|
static const int32 kMsgSetSize = 'size';
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
FontSelectionView::FontSelectionView(const char* name, const char* label,
|
||||||
|
bool separateStyles, const BFont* currentFont)
|
||||||
|
:
|
||||||
|
BHandler(name),
|
||||||
|
fMessage(NULL),
|
||||||
|
fTarget(NULL)
|
||||||
|
{
|
||||||
|
if (currentFont == NULL)
|
||||||
|
fCurrentFont = _DefaultFont();
|
||||||
|
else
|
||||||
|
fCurrentFont = *currentFont;
|
||||||
|
|
||||||
|
fSavedFont = fCurrentFont;
|
||||||
|
|
||||||
|
fSizesMenu = new BPopUpMenu("size menu");
|
||||||
|
fFontsMenu = new BPopUpMenu("font menu");
|
||||||
|
|
||||||
|
// font menu
|
||||||
|
fFontsMenuField = new BMenuField("fonts", label, fFontsMenu, B_WILL_DRAW);
|
||||||
|
fFontsMenuField->SetFont(be_bold_font);
|
||||||
|
|
||||||
|
// styles menu, if desired
|
||||||
|
if (separateStyles) {
|
||||||
|
fStylesMenu = new BPopUpMenu("styles menu");
|
||||||
|
fStylesMenuField = new BMenuField("styles", B_TRANSLATE("Style:"),
|
||||||
|
fStylesMenu, B_WILL_DRAW);
|
||||||
|
} else {
|
||||||
|
fStylesMenu = NULL;
|
||||||
|
fStylesMenuField = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// size menu
|
||||||
|
fSizesMenuField = new BMenuField("size", B_TRANSLATE("Size:"), fSizesMenu,
|
||||||
|
B_WILL_DRAW);
|
||||||
|
fSizesMenuField->SetAlignment(B_ALIGN_RIGHT);
|
||||||
|
|
||||||
|
// preview
|
||||||
|
fPreviewText = new BStringView("preview text",
|
||||||
|
B_TRANSLATE_COMMENT("The quick brown fox jumps over the lazy dog.",
|
||||||
|
"Don't translate this literally ! Use a phrase showing all "
|
||||||
|
"chars from A to Z."));
|
||||||
|
|
||||||
|
fPreviewText->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED,
|
||||||
|
B_SIZE_UNLIMITED));
|
||||||
|
fPreviewText->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||||
|
1.65));
|
||||||
|
fPreviewText->SetAlignment(B_ALIGN_RIGHT);
|
||||||
|
_UpdateFontPreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FontSelectionView::~FontSelectionView()
|
||||||
|
{
|
||||||
|
// Some controls may not have been attached...
|
||||||
|
if (!fPreviewText->Window())
|
||||||
|
delete fPreviewText;
|
||||||
|
if (!fSizesMenuField->Window())
|
||||||
|
delete fSizesMenuField;
|
||||||
|
if (fStylesMenuField && !fStylesMenuField->Window())
|
||||||
|
delete fStylesMenuField;
|
||||||
|
if (!fFontsMenuField->Window())
|
||||||
|
delete fFontsMenuField;
|
||||||
|
|
||||||
|
delete fMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::AttachedToLooper()
|
||||||
|
{
|
||||||
|
_BuildSizesMenu();
|
||||||
|
UpdateFontsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case kMsgSetSize:
|
||||||
|
{
|
||||||
|
int32 size;
|
||||||
|
if (message->FindInt32("size", &size) != B_OK
|
||||||
|
|| size == fCurrentFont.Size())
|
||||||
|
break;
|
||||||
|
|
||||||
|
fCurrentFont.SetSize(size);
|
||||||
|
_UpdateFontPreview();
|
||||||
|
_Invoke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kMsgSetFamily:
|
||||||
|
{
|
||||||
|
const char* family;
|
||||||
|
if (message->FindString("family", &family) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
font_style style;
|
||||||
|
fCurrentFont.GetFamilyAndStyle(NULL, &style);
|
||||||
|
|
||||||
|
BMenuItem* familyItem = fFontsMenu->FindItem(family);
|
||||||
|
if (familyItem != NULL) {
|
||||||
|
_SelectCurrentFont(false);
|
||||||
|
|
||||||
|
BMenuItem* styleItem;
|
||||||
|
if (fStylesMenuField != NULL)
|
||||||
|
styleItem = fStylesMenuField->Menu()->FindMarked();
|
||||||
|
else {
|
||||||
|
styleItem = familyItem->Submenu()->FindItem(style);
|
||||||
|
if (styleItem == NULL)
|
||||||
|
styleItem = familyItem->Submenu()->ItemAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleItem != NULL) {
|
||||||
|
styleItem->SetMarked(true);
|
||||||
|
fCurrentFont.SetFamilyAndStyle(family, styleItem->Label());
|
||||||
|
_UpdateFontPreview();
|
||||||
|
}
|
||||||
|
if (fStylesMenuField != NULL)
|
||||||
|
_AddStylesToMenu(fCurrentFont, fStylesMenuField->Menu());
|
||||||
|
}
|
||||||
|
|
||||||
|
_Invoke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kMsgSetStyle:
|
||||||
|
{
|
||||||
|
const char* family;
|
||||||
|
const char* style;
|
||||||
|
if (message->FindString("family", &family) != B_OK
|
||||||
|
|| message->FindString("style", &style) != B_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
BMenuItem *familyItem = fFontsMenu->FindItem(family);
|
||||||
|
if (!familyItem)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_SelectCurrentFont(false);
|
||||||
|
familyItem->SetMarked(true);
|
||||||
|
|
||||||
|
fCurrentFont.SetFamilyAndStyle(family, style);
|
||||||
|
_UpdateFontPreview();
|
||||||
|
_Invoke();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
BHandler::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::SetMessage(BMessage* message)
|
||||||
|
{
|
||||||
|
delete fMessage;
|
||||||
|
fMessage = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::SetTarget(BHandler* target)
|
||||||
|
{
|
||||||
|
fTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::SetFont(const BFont& font, float size)
|
||||||
|
{
|
||||||
|
BFont resizedFont(font);
|
||||||
|
resizedFont.SetSize(size);
|
||||||
|
SetFont(resizedFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::SetFont(const BFont& font)
|
||||||
|
{
|
||||||
|
if (font == fCurrentFont && font == fSavedFont)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_SelectCurrentFont(false);
|
||||||
|
fSavedFont = fCurrentFont = font;
|
||||||
|
_UpdateFontPreview();
|
||||||
|
|
||||||
|
_SelectCurrentFont(true);
|
||||||
|
_SelectCurrentSize(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::SetSize(float size)
|
||||||
|
{
|
||||||
|
SetFont(fCurrentFont, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BFont&
|
||||||
|
FontSelectionView::Font() const
|
||||||
|
{
|
||||||
|
return fCurrentFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::SetDefaults()
|
||||||
|
{
|
||||||
|
BFont defaultFont = _DefaultFont();
|
||||||
|
if (defaultFont == fCurrentFont)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_SelectCurrentFont(false);
|
||||||
|
|
||||||
|
fCurrentFont = defaultFont;
|
||||||
|
_UpdateFontPreview();
|
||||||
|
|
||||||
|
_SelectCurrentFont(true);
|
||||||
|
_SelectCurrentSize(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::Revert()
|
||||||
|
{
|
||||||
|
if (!IsRevertable())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_SelectCurrentFont(false);
|
||||||
|
|
||||||
|
fCurrentFont = fSavedFont;
|
||||||
|
_UpdateFontPreview();
|
||||||
|
|
||||||
|
_SelectCurrentFont(true);
|
||||||
|
_SelectCurrentSize(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FontSelectionView::IsDefaultable()
|
||||||
|
{
|
||||||
|
return fCurrentFont != _DefaultFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
FontSelectionView::IsRevertable()
|
||||||
|
{
|
||||||
|
return fCurrentFont != fSavedFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::UpdateFontsMenu()
|
||||||
|
{
|
||||||
|
int32 numFamilies = count_font_families();
|
||||||
|
|
||||||
|
fFontsMenu->RemoveItems(0, fFontsMenu->CountItems(), true);
|
||||||
|
|
||||||
|
BFont font = fCurrentFont;
|
||||||
|
|
||||||
|
font_family currentFamily;
|
||||||
|
font_style currentStyle;
|
||||||
|
font.GetFamilyAndStyle(¤tFamily, ¤tStyle);
|
||||||
|
|
||||||
|
for (int32 i = 0; i < numFamilies; i++) {
|
||||||
|
font_family family;
|
||||||
|
uint32 flags;
|
||||||
|
if (get_font_family(i, &family, &flags) != B_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// if we're setting the fixed font, we only want to show fixed fonts
|
||||||
|
if (!strcmp(Name(), "fixed") && (flags & B_IS_FIXED) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
font.SetFamilyAndFace(family, B_REGULAR_FACE);
|
||||||
|
|
||||||
|
BMessage* message = new BMessage(kMsgSetFamily);
|
||||||
|
message->AddString("family", family);
|
||||||
|
message->AddString("name", Name());
|
||||||
|
|
||||||
|
BMenuItem* familyItem;
|
||||||
|
if (fStylesMenuField != NULL) {
|
||||||
|
familyItem = new BMenuItem(family, message);
|
||||||
|
} else {
|
||||||
|
// Each family item has a submenu with all styles for that font.
|
||||||
|
BMenu* stylesMenu = new BMenu(family);
|
||||||
|
_AddStylesToMenu(font, stylesMenu);
|
||||||
|
familyItem = new BMenuItem(stylesMenu, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
familyItem->SetMarked(strcmp(family, currentFamily) == 0);
|
||||||
|
fFontsMenu->AddItem(familyItem);
|
||||||
|
familyItem->SetTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate styles menu for only the current font.
|
||||||
|
if (fStylesMenuField != NULL)
|
||||||
|
_AddStylesToMenu(fCurrentFont, fStylesMenuField->Menu());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
FontSelectionView::CreateSizesLabelLayoutItem()
|
||||||
|
{
|
||||||
|
return fSizesMenuField->CreateLabelLayoutItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
FontSelectionView::CreateSizesMenuBarLayoutItem()
|
||||||
|
{
|
||||||
|
return fSizesMenuField->CreateMenuBarLayoutItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
FontSelectionView::CreateFontsLabelLayoutItem()
|
||||||
|
{
|
||||||
|
return fFontsMenuField->CreateLabelLayoutItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
FontSelectionView::CreateFontsMenuBarLayoutItem()
|
||||||
|
{
|
||||||
|
return fFontsMenuField->CreateMenuBarLayoutItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
FontSelectionView::CreateStylesLabelLayoutItem()
|
||||||
|
{
|
||||||
|
if (fStylesMenuField)
|
||||||
|
return fStylesMenuField->CreateLabelLayoutItem();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
FontSelectionView::CreateStylesMenuBarLayoutItem()
|
||||||
|
{
|
||||||
|
if (fStylesMenuField)
|
||||||
|
return fStylesMenuField->CreateMenuBarLayoutItem();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
FontSelectionView::PreviewBox() const
|
||||||
|
{
|
||||||
|
return fPreviewText;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::_Invoke()
|
||||||
|
{
|
||||||
|
if (fTarget != NULL && fTarget->Looper() != NULL && fMessage != NULL) {
|
||||||
|
BMessage message(*fMessage);
|
||||||
|
fTarget->Looper()->PostMessage(&message, fTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BFont
|
||||||
|
FontSelectionView::_DefaultFont() const
|
||||||
|
{
|
||||||
|
if (strcmp(Name(), "bold") == 0)
|
||||||
|
return *be_bold_font;
|
||||||
|
if (strcmp(Name(), "fixed") == 0)
|
||||||
|
return *be_fixed_font;
|
||||||
|
else
|
||||||
|
return *be_plain_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::_SelectCurrentFont(bool select)
|
||||||
|
{
|
||||||
|
font_family family;
|
||||||
|
font_style style;
|
||||||
|
fCurrentFont.GetFamilyAndStyle(&family, &style);
|
||||||
|
|
||||||
|
BMenuItem *item = fFontsMenu->FindItem(family);
|
||||||
|
if (item != NULL) {
|
||||||
|
item->SetMarked(select);
|
||||||
|
|
||||||
|
if (item->Submenu() != NULL) {
|
||||||
|
item = item->Submenu()->FindItem(style);
|
||||||
|
if (item != NULL)
|
||||||
|
item->SetMarked(select);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::_SelectCurrentSize(bool select)
|
||||||
|
{
|
||||||
|
char label[16];
|
||||||
|
snprintf(label, sizeof(label), "%ld", (int32)fCurrentFont.Size());
|
||||||
|
|
||||||
|
BMenuItem* item = fSizesMenu->FindItem(label);
|
||||||
|
if (item != NULL)
|
||||||
|
item->SetMarked(select);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::_UpdateFontPreview()
|
||||||
|
{
|
||||||
|
fPreviewText->SetFont(&fCurrentFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::_BuildSizesMenu()
|
||||||
|
{
|
||||||
|
const int32 sizes[] = {7, 8, 9, 10, 11, 12, 13, 14, 18, 21, 24, 0};
|
||||||
|
|
||||||
|
// build size menu
|
||||||
|
for (int32 i = 0; sizes[i]; i++) {
|
||||||
|
int32 size = sizes[i];
|
||||||
|
if (size < kMinSize || size > kMaxSize)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char label[32];
|
||||||
|
snprintf(label, sizeof(label), "%ld", size);
|
||||||
|
|
||||||
|
BMessage* message = new BMessage(kMsgSetSize);
|
||||||
|
message->AddInt32("size", size);
|
||||||
|
message->AddString("name", Name());
|
||||||
|
|
||||||
|
BMenuItem* item = new BMenuItem(label, message);
|
||||||
|
if (size == fCurrentFont.Size())
|
||||||
|
item->SetMarked(true);
|
||||||
|
|
||||||
|
fSizesMenu->AddItem(item);
|
||||||
|
item->SetTarget(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
FontSelectionView::_AddStylesToMenu(const BFont& font, BMenu* stylesMenu) const
|
||||||
|
{
|
||||||
|
stylesMenu->RemoveItems(0, stylesMenu->CountItems(), true);
|
||||||
|
stylesMenu->SetRadioMode(true);
|
||||||
|
|
||||||
|
font_family family;
|
||||||
|
font_style style;
|
||||||
|
font.GetFamilyAndStyle(&family, &style);
|
||||||
|
BString currentStyle(style);
|
||||||
|
|
||||||
|
int32 numStyles = count_font_styles(family);
|
||||||
|
|
||||||
|
for (int32 j = 0; j < numStyles; j++) {
|
||||||
|
if (get_font_style(family, j, &style) != B_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BMessage* message = new BMessage(kMsgSetStyle);
|
||||||
|
message->AddString("family", (char*)family);
|
||||||
|
message->AddString("style", (char*)style);
|
||||||
|
|
||||||
|
BMenuItem* item = new BMenuItem(style, message);
|
||||||
|
item->SetMarked(currentStyle == style);
|
||||||
|
|
||||||
|
stylesMenu->AddItem(item);
|
||||||
|
item->SetTarget(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2001-2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Mark Hogben
|
||||||
|
* DarkWyrm <[email protected]>
|
||||||
|
* Axel Dörfler, [email protected]
|
||||||
|
* Philippe Saint-Pierre, [email protected]
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*/
|
||||||
|
#ifndef FONT_SELECTION_VIEW_H
|
||||||
|
#define FONT_SELECTION_VIEW_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Font.h>
|
||||||
|
#include <Handler.h>
|
||||||
|
|
||||||
|
class BLayoutItem;
|
||||||
|
class BBox;
|
||||||
|
class BMenu;
|
||||||
|
class BMenuField;
|
||||||
|
class BPopUpMenu;
|
||||||
|
class BStringView;
|
||||||
|
class BView;
|
||||||
|
|
||||||
|
|
||||||
|
class FontSelectionView : public BHandler {
|
||||||
|
public:
|
||||||
|
FontSelectionView(const char* name,
|
||||||
|
const char* label, bool separateStyles,
|
||||||
|
const BFont* font = NULL);
|
||||||
|
virtual ~FontSelectionView();
|
||||||
|
|
||||||
|
void AttachedToLooper();
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
void SetMessage(BMessage* message);
|
||||||
|
void SetTarget(BHandler* target);
|
||||||
|
|
||||||
|
void SetFont(const BFont& font, float size);
|
||||||
|
void SetFont(const BFont& font);
|
||||||
|
void SetSize(float size);
|
||||||
|
const BFont& Font() const;
|
||||||
|
|
||||||
|
void SetDefaults();
|
||||||
|
void Revert();
|
||||||
|
bool IsDefaultable();
|
||||||
|
bool IsRevertable();
|
||||||
|
|
||||||
|
void UpdateFontsMenu();
|
||||||
|
|
||||||
|
BLayoutItem* CreateSizesLabelLayoutItem();
|
||||||
|
BLayoutItem* CreateSizesMenuBarLayoutItem();
|
||||||
|
|
||||||
|
BLayoutItem* CreateFontsLabelLayoutItem();
|
||||||
|
BLayoutItem* CreateFontsMenuBarLayoutItem();
|
||||||
|
|
||||||
|
BLayoutItem* CreateStylesLabelLayoutItem();
|
||||||
|
BLayoutItem* CreateStylesMenuBarLayoutItem();
|
||||||
|
|
||||||
|
BView* PreviewBox() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _Invoke();
|
||||||
|
|
||||||
|
BFont _DefaultFont() const;
|
||||||
|
void _SelectCurrentFont(bool select);
|
||||||
|
void _SelectCurrentSize(bool select);
|
||||||
|
void _UpdateFontPreview();
|
||||||
|
void _BuildSizesMenu();
|
||||||
|
void _AddStylesToMenu(const BFont& font,
|
||||||
|
BMenu* menu) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BMenuField* fFontsMenuField;
|
||||||
|
BMenuField* fStylesMenuField;
|
||||||
|
BMenuField* fSizesMenuField;
|
||||||
|
BPopUpMenu* fFontsMenu;
|
||||||
|
BPopUpMenu* fStylesMenu;
|
||||||
|
BPopUpMenu* fSizesMenu;
|
||||||
|
BStringView* fPreviewText;
|
||||||
|
|
||||||
|
BFont fSavedFont;
|
||||||
|
BFont fCurrentFont;
|
||||||
|
|
||||||
|
BMessage* fMessage;
|
||||||
|
BHandler* fTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FONT_SELECTION_VIEW_H
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Stephan Aßmus <[email protected]>. All rights reserved.
|
||||||
|
* Copyright 2004-2007, Ingo Weinhold <[email protected]>. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef HASH_KEYS_H
|
||||||
|
#define HASH_KEYS_H
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO: Move here from HashMap.h and adapt all clients.
|
||||||
|
// HashKey32
|
||||||
|
template<typename Value>
|
||||||
|
struct HashKey32 {
|
||||||
|
HashKey32() {}
|
||||||
|
HashKey32(const Value& value) : value(value) {}
|
||||||
|
|
||||||
|
uint32 GetHashCode() const
|
||||||
|
{
|
||||||
|
return (uint32)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKey32<Value> operator=(const HashKey32<Value>& other)
|
||||||
|
{
|
||||||
|
value = other.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const HashKey32<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value == other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const HashKey32<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value != other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// HashKey64
|
||||||
|
template<typename Value>
|
||||||
|
struct HashKey64 {
|
||||||
|
HashKey64() {}
|
||||||
|
HashKey64(const Value& value) : value(value) {}
|
||||||
|
|
||||||
|
uint32 GetHashCode() const
|
||||||
|
{
|
||||||
|
uint64 v = (uint64)value;
|
||||||
|
return (uint32)(v >> 32) ^ (uint32)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKey64<Value> operator=(const HashKey64<Value>& other)
|
||||||
|
{
|
||||||
|
value = other.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const HashKey64<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value == other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const HashKey64<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value != other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct HashKeyString {
|
||||||
|
HashKeyString() {}
|
||||||
|
HashKeyString(const BString& value) : value(value) {}
|
||||||
|
HashKeyString(const char* string) : value(string) {}
|
||||||
|
|
||||||
|
uint32 GetHashCode() const
|
||||||
|
{
|
||||||
|
// from the Dragon Book: a slightly modified hashpjw()
|
||||||
|
uint32 hash = 0;
|
||||||
|
const char* string = value.String();
|
||||||
|
if (string != NULL) {
|
||||||
|
for (; *string; string++) {
|
||||||
|
uint32 g = hash & 0xf0000000;
|
||||||
|
if (g != 0)
|
||||||
|
hash ^= g >> 24;
|
||||||
|
hash = (hash << 4) + *string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKeyString operator=(const HashKeyString& other)
|
||||||
|
{
|
||||||
|
value = other.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const HashKeyString& other) const
|
||||||
|
{
|
||||||
|
return (value == other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const HashKeyString& other) const
|
||||||
|
{
|
||||||
|
return (value != other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
BString value;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using BPrivate::HashKeyString;
|
||||||
|
|
||||||
|
#endif // HASH_KEYS_H
|
||||||
@@ -0,0 +1,481 @@
|
|||||||
|
// HashMap.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2004-2007, Ingo Weinhold ([email protected])
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// Except as contained in this notice, the name of a copyright holder shall
|
||||||
|
// not be used in advertising or otherwise to promote the sale, use or other
|
||||||
|
// dealings in this Software without prior written authorization of the
|
||||||
|
// copyright holder.
|
||||||
|
|
||||||
|
#ifndef HASH_MAP_H
|
||||||
|
#define HASH_MAP_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
|
#include "AutoLocker.h"
|
||||||
|
#include "OpenHashTable.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
// HashMapElement
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
class HashMapElement : public OpenHashElement {
|
||||||
|
private:
|
||||||
|
typedef HashMapElement<Key, Value> Element;
|
||||||
|
public:
|
||||||
|
|
||||||
|
HashMapElement() : OpenHashElement(), fKey(), fValue()
|
||||||
|
{
|
||||||
|
fNext = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 Hash() const
|
||||||
|
{
|
||||||
|
return fKey.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const OpenHashElement &_element) const
|
||||||
|
{
|
||||||
|
const Element &element = static_cast<const Element&>(_element);
|
||||||
|
return (fKey == element.fKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Adopt(Element &element)
|
||||||
|
{
|
||||||
|
fKey = element.fKey;
|
||||||
|
fValue = element.fValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key fKey;
|
||||||
|
Value fValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
// HashMap
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
class HashMap {
|
||||||
|
public:
|
||||||
|
class Entry {
|
||||||
|
public:
|
||||||
|
Entry() {}
|
||||||
|
Entry(const Key& key, Value value) : key(key), value(value) {}
|
||||||
|
|
||||||
|
Key key;
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Iterator {
|
||||||
|
private:
|
||||||
|
typedef HashMapElement<Key, Value> Element;
|
||||||
|
public:
|
||||||
|
Iterator(const Iterator& other)
|
||||||
|
:
|
||||||
|
fMap(other.fMap),
|
||||||
|
fIndex(other.fIndex),
|
||||||
|
fElement(other.fElement),
|
||||||
|
fLastElement(other.fElement)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasNext() const
|
||||||
|
{
|
||||||
|
return fElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry Next()
|
||||||
|
{
|
||||||
|
if (!fElement)
|
||||||
|
return Entry();
|
||||||
|
Entry result(fElement->fKey, fElement->fValue);
|
||||||
|
_FindNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* NextValue()
|
||||||
|
{
|
||||||
|
if (fElement == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Value* value = &fElement->fValue;
|
||||||
|
_FindNext();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry Remove()
|
||||||
|
{
|
||||||
|
if (!fLastElement)
|
||||||
|
return Entry();
|
||||||
|
Entry result(fLastElement->fKey, fLastElement->fValue);
|
||||||
|
fMap->fTable.Remove(fLastElement, true);
|
||||||
|
fLastElement = NULL;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator& operator=(const Iterator& other)
|
||||||
|
{
|
||||||
|
fMap = other.fMap;
|
||||||
|
fIndex = other.fIndex;
|
||||||
|
fElement = other.fElement;
|
||||||
|
fLastElement = other.fLastElement;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Iterator(const HashMap<Key, Value>* map)
|
||||||
|
:
|
||||||
|
fMap(const_cast<HashMap<Key, Value>*>(map)),
|
||||||
|
fIndex(0),
|
||||||
|
fElement(NULL),
|
||||||
|
fLastElement(NULL)
|
||||||
|
{
|
||||||
|
// find first
|
||||||
|
_FindNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FindNext()
|
||||||
|
{
|
||||||
|
fLastElement = fElement;
|
||||||
|
if (fElement && fElement->fNext >= 0) {
|
||||||
|
fElement = fMap->fTable.ElementAt(fElement->fNext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fElement = NULL;
|
||||||
|
int32 arraySize = fMap->fTable.ArraySize();
|
||||||
|
for (; !fElement && fIndex < arraySize; fIndex++)
|
||||||
|
fElement = fMap->fTable.FindFirst(fIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class HashMap<Key, Value>;
|
||||||
|
|
||||||
|
HashMap<Key, Value>* fMap;
|
||||||
|
int32 fIndex;
|
||||||
|
Element* fElement;
|
||||||
|
Element* fLastElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
HashMap();
|
||||||
|
~HashMap();
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
status_t Put(const Key& key, Value value);
|
||||||
|
Value Remove(const Key& key);
|
||||||
|
void Clear();
|
||||||
|
Value Get(const Key& key) const;
|
||||||
|
bool Get(const Key& key, Value*& _value) const;
|
||||||
|
|
||||||
|
bool ContainsKey(const Key& key) const;
|
||||||
|
|
||||||
|
int32 Size() const;
|
||||||
|
|
||||||
|
Iterator GetIterator() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef HashMapElement<Key, Value> Element;
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Element *_FindElement(const Key& key) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OpenHashElementArray<Element> fElementArray;
|
||||||
|
OpenHashTable<Element, OpenHashElementArray<Element> > fTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
// SynchronizedHashMap
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
class SynchronizedHashMap : public BLocker {
|
||||||
|
public:
|
||||||
|
typedef struct HashMap<Key, Value>::Entry Entry;
|
||||||
|
typedef struct HashMap<Key, Value>::Iterator Iterator;
|
||||||
|
|
||||||
|
SynchronizedHashMap() : BLocker("synchronized hash map") {}
|
||||||
|
~SynchronizedHashMap() { Lock(); }
|
||||||
|
|
||||||
|
status_t InitCheck() const
|
||||||
|
{
|
||||||
|
return fMap.InitCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Put(const Key& key, Value value)
|
||||||
|
{
|
||||||
|
MapLocker locker(this);
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return B_ERROR;
|
||||||
|
return fMap.Put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value Remove(const Key& key)
|
||||||
|
{
|
||||||
|
MapLocker locker(this);
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return Value();
|
||||||
|
return fMap.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
MapLocker locker(this);
|
||||||
|
return fMap.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Value Get(const Key& key) const
|
||||||
|
{
|
||||||
|
const BLocker* lock = this;
|
||||||
|
MapLocker locker(const_cast<BLocker*>(lock));
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return Value();
|
||||||
|
return fMap.Get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ContainsKey(const Key& key) const
|
||||||
|
{
|
||||||
|
const BLocker* lock = this;
|
||||||
|
MapLocker locker(const_cast<BLocker*>(lock));
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return false;
|
||||||
|
return fMap.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Size() const
|
||||||
|
{
|
||||||
|
const BLocker* lock = this;
|
||||||
|
MapLocker locker(const_cast<BLocker*>(lock));
|
||||||
|
return fMap.Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator GetIterator()
|
||||||
|
{
|
||||||
|
return fMap.GetIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for debugging only
|
||||||
|
const HashMap<Key, Value>& GetUnsynchronizedMap() const { return fMap; }
|
||||||
|
HashMap<Key, Value>& GetUnsynchronizedMap() { return fMap; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef AutoLocker<BLocker> MapLocker;
|
||||||
|
|
||||||
|
HashMap<Key, Value> fMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
// HashKey32
|
||||||
|
template<typename Value>
|
||||||
|
struct HashKey32 {
|
||||||
|
HashKey32() {}
|
||||||
|
HashKey32(const Value& value) : value(value) {}
|
||||||
|
|
||||||
|
uint32 GetHashCode() const
|
||||||
|
{
|
||||||
|
return (uint32)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKey32<Value> operator=(const HashKey32<Value>& other)
|
||||||
|
{
|
||||||
|
value = other.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const HashKey32<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value == other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const HashKey32<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value != other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// HashKey64
|
||||||
|
template<typename Value>
|
||||||
|
struct HashKey64 {
|
||||||
|
HashKey64() {}
|
||||||
|
HashKey64(const Value& value) : value(value) {}
|
||||||
|
|
||||||
|
uint32 GetHashCode() const
|
||||||
|
{
|
||||||
|
uint64 v = (uint64)value;
|
||||||
|
return (uint32)(v >> 32) ^ (uint32)v;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashKey64<Value> operator=(const HashKey64<Value>& other)
|
||||||
|
{
|
||||||
|
value = other.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const HashKey64<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value == other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const HashKey64<Value>& other) const
|
||||||
|
{
|
||||||
|
return (value != other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// HashMap
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
HashMap<Key, Value>::HashMap()
|
||||||
|
:
|
||||||
|
fElementArray(1000),
|
||||||
|
fTable(1000, &fElementArray)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
HashMap<Key, Value>::~HashMap()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitCheck
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
status_t
|
||||||
|
HashMap<Key, Value>::InitCheck() const
|
||||||
|
{
|
||||||
|
return (fTable.InitCheck() && fElementArray.InitCheck()
|
||||||
|
? B_OK : B_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
status_t
|
||||||
|
HashMap<Key, Value>::Put(const Key& key, Value value)
|
||||||
|
{
|
||||||
|
Element* element = _FindElement(key);
|
||||||
|
if (element) {
|
||||||
|
// already contains the key: just set the new value
|
||||||
|
element->fValue = value;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
// does not contain the key yet: add an element
|
||||||
|
element = fTable.Add(key.GetHashCode());
|
||||||
|
if (!element)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
element->fKey = key;
|
||||||
|
element->fValue = value;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
Value
|
||||||
|
HashMap<Key, Value>::Remove(const Key& key)
|
||||||
|
{
|
||||||
|
Value value = Value();
|
||||||
|
if (Element* element = _FindElement(key)) {
|
||||||
|
value = element->fValue;
|
||||||
|
fTable.Remove(element);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
void
|
||||||
|
HashMap<Key, Value>::Clear()
|
||||||
|
{
|
||||||
|
fTable.RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
Value
|
||||||
|
HashMap<Key, Value>::Get(const Key& key) const
|
||||||
|
{
|
||||||
|
if (Element* element = _FindElement(key))
|
||||||
|
return element->fValue;
|
||||||
|
return Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
bool
|
||||||
|
HashMap<Key, Value>::Get(const Key& key, Value*& _value) const
|
||||||
|
{
|
||||||
|
if (Element* element = _FindElement(key)) {
|
||||||
|
_value = &element->fValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsKey
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
bool
|
||||||
|
HashMap<Key, Value>::ContainsKey(const Key& key) const
|
||||||
|
{
|
||||||
|
return _FindElement(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
int32
|
||||||
|
HashMap<Key, Value>::Size() const
|
||||||
|
{
|
||||||
|
return fTable.CountElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIterator
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
struct HashMap<Key, Value>::Iterator
|
||||||
|
HashMap<Key, Value>::GetIterator() const
|
||||||
|
{
|
||||||
|
return Iterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// _FindElement
|
||||||
|
template<typename Key, typename Value>
|
||||||
|
struct HashMap<Key, Value>::Element *
|
||||||
|
HashMap<Key, Value>::_FindElement(const Key& key) const
|
||||||
|
{
|
||||||
|
Element* element = fTable.FindFirst(key.GetHashCode());
|
||||||
|
while (element && element->fKey != key) {
|
||||||
|
if (element->fNext >= 0)
|
||||||
|
element = fTable.ElementAt(element->fNext);
|
||||||
|
else
|
||||||
|
element = NULL;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using BPrivate::HashMap;
|
||||||
|
using BPrivate::HashKey32;
|
||||||
|
using BPrivate::HashKey64;
|
||||||
|
using BPrivate::SynchronizedHashMap;
|
||||||
|
|
||||||
|
#endif // HASH_MAP_H
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
// HashSet.h
|
||||||
|
//
|
||||||
|
// Copyright (c) 2004, Ingo Weinhold ([email protected])
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
// Except as contained in this notice, the name of a copyright holder shall
|
||||||
|
// not be used in advertising or otherwise to promote the sale, use or other
|
||||||
|
// dealings in this Software without prior written authorization of the
|
||||||
|
// copyright holder.
|
||||||
|
|
||||||
|
#ifndef HASH_SET_H
|
||||||
|
#define HASH_SET_H
|
||||||
|
|
||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
|
#include "AutoLocker.h"
|
||||||
|
#include "OpenHashTable.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
// HashSetElement
|
||||||
|
template<typename Key>
|
||||||
|
class HashSetElement : public OpenHashElement {
|
||||||
|
private:
|
||||||
|
typedef HashSetElement<Key> Element;
|
||||||
|
public:
|
||||||
|
|
||||||
|
HashSetElement() : OpenHashElement(), fKey()
|
||||||
|
{
|
||||||
|
fNext = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 Hash() const
|
||||||
|
{
|
||||||
|
return fKey.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const OpenHashElement &_element) const
|
||||||
|
{
|
||||||
|
const Element &element = static_cast<const Element&>(_element);
|
||||||
|
return (fKey == element.fKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Adopt(Element &element)
|
||||||
|
{
|
||||||
|
fKey = element.fKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key fKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
// HashSet
|
||||||
|
template<typename Key>
|
||||||
|
class HashSet {
|
||||||
|
public:
|
||||||
|
class Iterator {
|
||||||
|
private:
|
||||||
|
typedef HashSetElement<Key> Element;
|
||||||
|
public:
|
||||||
|
Iterator(const Iterator& other)
|
||||||
|
: fSet(other.fSet),
|
||||||
|
fIndex(other.fIndex),
|
||||||
|
fElement(other.fElement),
|
||||||
|
fLastElement(other.fElement)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasNext() const
|
||||||
|
{
|
||||||
|
return fElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
Key Next()
|
||||||
|
{
|
||||||
|
if (!fElement)
|
||||||
|
return Key();
|
||||||
|
Key result(fElement->fKey);
|
||||||
|
_FindNext();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Remove()
|
||||||
|
{
|
||||||
|
if (!fLastElement)
|
||||||
|
return false;
|
||||||
|
fSet->fTable.Remove(fLastElement);
|
||||||
|
fLastElement = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator& operator=(const Iterator& other)
|
||||||
|
{
|
||||||
|
fSet = other.fSet;
|
||||||
|
fIndex = other.fIndex;
|
||||||
|
fElement = other.fElement;
|
||||||
|
fLastElement = other.fLastElement;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Iterator(HashSet<Key>* map)
|
||||||
|
: fSet(map),
|
||||||
|
fIndex(0),
|
||||||
|
fElement(NULL),
|
||||||
|
fLastElement(NULL)
|
||||||
|
{
|
||||||
|
// find first
|
||||||
|
_FindNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _FindNext()
|
||||||
|
{
|
||||||
|
fLastElement = fElement;
|
||||||
|
if (fElement && fElement->fNext >= 0) {
|
||||||
|
fElement = fSet->fTable.ElementAt(fElement->fNext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fElement = NULL;
|
||||||
|
int32 arraySize = fSet->fTable.ArraySize();
|
||||||
|
for (; !fElement && fIndex < arraySize; fIndex++)
|
||||||
|
fElement = fSet->fTable.FindFirst(fIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class HashSet<Key>;
|
||||||
|
|
||||||
|
HashSet<Key>* fSet;
|
||||||
|
int32 fIndex;
|
||||||
|
Element* fElement;
|
||||||
|
Element* fLastElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
HashSet();
|
||||||
|
~HashSet();
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
|
||||||
|
status_t Add(const Key& key);
|
||||||
|
bool Remove(const Key& key);
|
||||||
|
void Clear();
|
||||||
|
bool Contains(const Key& key) const;
|
||||||
|
|
||||||
|
int32 Size() const;
|
||||||
|
bool IsEmpty() const { return Size() == 0; }
|
||||||
|
|
||||||
|
Iterator GetIterator();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef HashSetElement<Key> Element;
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Element *_FindElement(const Key& key) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
OpenHashElementArray<Element> fElementArray;
|
||||||
|
OpenHashTable<Element, OpenHashElementArray<Element> > fTable;
|
||||||
|
};
|
||||||
|
|
||||||
|
// SynchronizedHashSet
|
||||||
|
template<typename Key>
|
||||||
|
class SynchronizedHashSet : public BLocker {
|
||||||
|
public:
|
||||||
|
typedef struct HashSet<Key>::Iterator Iterator;
|
||||||
|
|
||||||
|
SynchronizedHashSet() : BLocker("synchronized hash set") {}
|
||||||
|
~SynchronizedHashSet() { Lock(); }
|
||||||
|
|
||||||
|
status_t InitCheck() const
|
||||||
|
{
|
||||||
|
return fSet.InitCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t Add(const Key& key)
|
||||||
|
{
|
||||||
|
MapLocker locker(this);
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return B_ERROR;
|
||||||
|
return fSet.Add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Remove(const Key& key)
|
||||||
|
{
|
||||||
|
MapLocker locker(this);
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return false;
|
||||||
|
return fSet.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Contains(const Key& key) const
|
||||||
|
{
|
||||||
|
const BLocker* lock = this;
|
||||||
|
MapLocker locker(const_cast<BLocker*>(lock));
|
||||||
|
if (!locker.IsLocked())
|
||||||
|
return false;
|
||||||
|
return fSet.Contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 Size() const
|
||||||
|
{
|
||||||
|
const BLocker* lock = this;
|
||||||
|
MapLocker locker(const_cast<BLocker*>(lock));
|
||||||
|
return fSet.Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator GetIterator()
|
||||||
|
{
|
||||||
|
return fSet.GetIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for debugging only
|
||||||
|
const HashSet<Key>& GetUnsynchronizedSet() const { return fSet; }
|
||||||
|
HashSet<Key>& GetUnsynchronizedSet() { return fSet; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
typedef AutoLocker<BLocker> MapLocker;
|
||||||
|
|
||||||
|
HashSet<Key> fSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
// HashSet
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
template<typename Key>
|
||||||
|
HashSet<Key>::HashSet()
|
||||||
|
: fElementArray(1000),
|
||||||
|
fTable(1000, &fElementArray)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
template<typename Key>
|
||||||
|
HashSet<Key>::~HashSet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitCheck
|
||||||
|
template<typename Key>
|
||||||
|
status_t
|
||||||
|
HashSet<Key>::InitCheck() const
|
||||||
|
{
|
||||||
|
return (fTable.InitCheck() && fElementArray.InitCheck()
|
||||||
|
? B_OK : B_NO_MEMORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add
|
||||||
|
template<typename Key>
|
||||||
|
status_t
|
||||||
|
HashSet<Key>::Add(const Key& key)
|
||||||
|
{
|
||||||
|
if (Contains(key))
|
||||||
|
return B_OK;
|
||||||
|
Element* element = fTable.Add(key.GetHashCode());
|
||||||
|
if (!element)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
element->fKey = key;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove
|
||||||
|
template<typename Key>
|
||||||
|
bool
|
||||||
|
HashSet<Key>::Remove(const Key& key)
|
||||||
|
{
|
||||||
|
if (Element* element = _FindElement(key)) {
|
||||||
|
fTable.Remove(element);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
template<typename Key>
|
||||||
|
void
|
||||||
|
HashSet<Key>::Clear()
|
||||||
|
{
|
||||||
|
fTable.RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains
|
||||||
|
template<typename Key>
|
||||||
|
bool
|
||||||
|
HashSet<Key>::Contains(const Key& key) const
|
||||||
|
{
|
||||||
|
return _FindElement(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size
|
||||||
|
template<typename Key>
|
||||||
|
int32
|
||||||
|
HashSet<Key>::Size() const
|
||||||
|
{
|
||||||
|
return fTable.CountElements();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIterator
|
||||||
|
template<typename Key>
|
||||||
|
struct HashSet<Key>::Iterator
|
||||||
|
HashSet<Key>::GetIterator()
|
||||||
|
{
|
||||||
|
return Iterator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// _FindElement
|
||||||
|
template<typename Key>
|
||||||
|
struct HashSet<Key>::Element *
|
||||||
|
HashSet<Key>::_FindElement(const Key& key) const
|
||||||
|
{
|
||||||
|
Element* element = fTable.FindFirst(key.GetHashCode());
|
||||||
|
while (element && element->fKey != key) {
|
||||||
|
if (element->fNext >= 0)
|
||||||
|
element = fTable.ElementAt(element->fNext);
|
||||||
|
else
|
||||||
|
element = NULL;
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using BPrivate::HashSet;
|
||||||
|
using BPrivate::SynchronizedHashSet;
|
||||||
|
|
||||||
|
#endif // HASH_SET_H
|
||||||
@@ -0,0 +1,929 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NOTE: this file is a duplicate of the version in Icon-O-Matic/generic
|
||||||
|
// it should be placed into a common folder for generic useful stuff
|
||||||
|
|
||||||
|
#include "IconButton.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <Control.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <Looper.h>
|
||||||
|
#include <Message.h>
|
||||||
|
#include <Mime.h>
|
||||||
|
#include <Path.h>
|
||||||
|
#include <Region.h>
|
||||||
|
#include <Resources.h>
|
||||||
|
#include <Roster.h>
|
||||||
|
#include <TranslationUtils.h>
|
||||||
|
#include <Window.h>
|
||||||
|
#include "IconUtils.h"
|
||||||
|
|
||||||
|
using std::nothrow;
|
||||||
|
|
||||||
|
// constructor
|
||||||
|
IconButton::IconButton(const char* name, uint32 id, const char* label,
|
||||||
|
BMessage* message, BHandler* target)
|
||||||
|
: BView(name, B_WILL_DRAW),
|
||||||
|
BInvoker(message, target),
|
||||||
|
fButtonState(STATE_ENABLED),
|
||||||
|
fID(id),
|
||||||
|
fNormalBitmap(NULL),
|
||||||
|
fDisabledBitmap(NULL),
|
||||||
|
fClickedBitmap(NULL),
|
||||||
|
fDisabledClickedBitmap(NULL),
|
||||||
|
fLabel(label),
|
||||||
|
fTargetCache(target)
|
||||||
|
{
|
||||||
|
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
IconButton::~IconButton()
|
||||||
|
{
|
||||||
|
_DeleteBitmaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageReceived
|
||||||
|
void
|
||||||
|
IconButton::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
default:
|
||||||
|
BView::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachedToWindow
|
||||||
|
void
|
||||||
|
IconButton::AttachedToWindow()
|
||||||
|
{
|
||||||
|
rgb_color background = B_TRANSPARENT_COLOR;
|
||||||
|
if (BView* parent = Parent()) {
|
||||||
|
background = parent->ViewColor();
|
||||||
|
if (background == B_TRANSPARENT_COLOR)
|
||||||
|
background = parent->LowColor();
|
||||||
|
}
|
||||||
|
if (background == B_TRANSPARENT_COLOR)
|
||||||
|
background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
SetLowColor(background);
|
||||||
|
|
||||||
|
SetTarget(fTargetCache);
|
||||||
|
if (!Target())
|
||||||
|
SetTarget(Window());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw
|
||||||
|
void
|
||||||
|
IconButton::Draw(BRect area)
|
||||||
|
{
|
||||||
|
rgb_color background = LowColor();
|
||||||
|
|
||||||
|
BRect r(Bounds());
|
||||||
|
|
||||||
|
if (be_control_look != NULL) {
|
||||||
|
uint32 flags = 0;
|
||||||
|
BBitmap* bitmap = fNormalBitmap;
|
||||||
|
if (!IsEnabled()) {
|
||||||
|
flags |= BControlLook::B_DISABLED;
|
||||||
|
bitmap = fDisabledBitmap;
|
||||||
|
}
|
||||||
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
||||||
|
flags |= BControlLook::B_ACTIVATED;
|
||||||
|
|
||||||
|
if (DrawBorder()) {
|
||||||
|
be_control_look->DrawButtonFrame(this, r, area, background,
|
||||||
|
background, flags);
|
||||||
|
be_control_look->DrawButtonBackground(this, r, area, background,
|
||||||
|
flags);
|
||||||
|
} else {
|
||||||
|
SetHighColor(background);
|
||||||
|
FillRect(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitmap && bitmap->IsValid()) {
|
||||||
|
float x = r.left + floorf((r.Width()
|
||||||
|
- bitmap->Bounds().Width()) / 2.0 + 0.5);
|
||||||
|
float y = r.top + floorf((r.Height()
|
||||||
|
- bitmap->Bounds().Height()) / 2.0 + 0.5);
|
||||||
|
BPoint point(x, y);
|
||||||
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
||||||
|
point += BPoint(1.0, 1.0);
|
||||||
|
if (bitmap->ColorSpace() == B_RGBA32
|
||||||
|
|| bitmap->ColorSpace() == B_RGBA32_BIG) {
|
||||||
|
SetDrawingMode(B_OP_ALPHA);
|
||||||
|
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
}
|
||||||
|
DrawBitmap(bitmap, point);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb_color lightShadow, shadow, darkShadow, light;
|
||||||
|
BBitmap* bitmap = fNormalBitmap;
|
||||||
|
// adjust colors and bitmap according to flags
|
||||||
|
if (IsEnabled()) {
|
||||||
|
lightShadow = tint_color(background, B_DARKEN_1_TINT);
|
||||||
|
shadow = tint_color(background, B_DARKEN_2_TINT);
|
||||||
|
darkShadow = tint_color(background, B_DARKEN_4_TINT);
|
||||||
|
light = tint_color(background, B_LIGHTEN_MAX_TINT);
|
||||||
|
SetHighColor(0, 0, 0, 255);
|
||||||
|
} else {
|
||||||
|
lightShadow = tint_color(background, 1.11);
|
||||||
|
shadow = tint_color(background, B_DARKEN_1_TINT);
|
||||||
|
darkShadow = tint_color(background, B_DARKEN_2_TINT);
|
||||||
|
light = tint_color(background, B_LIGHTEN_2_TINT);
|
||||||
|
bitmap = fDisabledBitmap;
|
||||||
|
SetHighColor(tint_color(background, B_DISABLED_LABEL_TINT));
|
||||||
|
}
|
||||||
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED)) {
|
||||||
|
if (IsEnabled()) {
|
||||||
|
// background = tint_color(background, B_DARKEN_2_TINT);
|
||||||
|
// background = tint_color(background, B_LIGHTEN_1_TINT);
|
||||||
|
background = tint_color(background, B_DARKEN_1_TINT);
|
||||||
|
bitmap = fClickedBitmap;
|
||||||
|
} else {
|
||||||
|
// background = tint_color(background, B_DARKEN_1_TINT);
|
||||||
|
// background = tint_color(background, (B_NO_TINT + B_LIGHTEN_1_TINT) / 2.0);
|
||||||
|
background = tint_color(background, (B_NO_TINT + B_DARKEN_1_TINT) / 2.0);
|
||||||
|
bitmap = fDisabledClickedBitmap;
|
||||||
|
}
|
||||||
|
// background
|
||||||
|
SetLowColor(background);
|
||||||
|
r.InsetBy(2.0, 2.0);
|
||||||
|
StrokeLine(r.LeftBottom(), r.LeftTop(), B_SOLID_LOW);
|
||||||
|
StrokeLine(r.LeftTop(), r.RightTop(), B_SOLID_LOW);
|
||||||
|
r.InsetBy(-2.0, -2.0);
|
||||||
|
}
|
||||||
|
// draw frame only if tracking
|
||||||
|
if (DrawBorder()) {
|
||||||
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
||||||
|
DrawPressedBorder(r, background, shadow, darkShadow, lightShadow, light);
|
||||||
|
else
|
||||||
|
DrawNormalBorder(r, background, shadow, darkShadow, lightShadow, light);
|
||||||
|
r.InsetBy(2.0, 2.0);
|
||||||
|
} else
|
||||||
|
_DrawFrame(r, background, background, background, background);
|
||||||
|
float width = Bounds().Width();
|
||||||
|
float height = Bounds().Height();
|
||||||
|
// bitmap
|
||||||
|
BRegion originalClippingRegion;
|
||||||
|
if (bitmap && bitmap->IsValid()) {
|
||||||
|
float x = floorf((width - bitmap->Bounds().Width()) / 2.0 + 0.5);
|
||||||
|
float y = floorf((height - bitmap->Bounds().Height()) / 2.0 + 0.5);
|
||||||
|
BPoint point(x, y);
|
||||||
|
if (_HasFlags(STATE_PRESSED) || _HasFlags(STATE_FORCE_PRESSED))
|
||||||
|
point += BPoint(1.0, 1.0);
|
||||||
|
if (bitmap->ColorSpace() == B_RGBA32 || bitmap->ColorSpace() == B_RGBA32_BIG) {
|
||||||
|
FillRect(r, B_SOLID_LOW);
|
||||||
|
SetDrawingMode(B_OP_ALPHA);
|
||||||
|
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
}
|
||||||
|
DrawBitmap(bitmap, point);
|
||||||
|
// constrain clipping region
|
||||||
|
BRegion region= originalClippingRegion;
|
||||||
|
GetClippingRegion(®ion);
|
||||||
|
region.Exclude(bitmap->Bounds().OffsetByCopy(point));
|
||||||
|
ConstrainClippingRegion(®ion);
|
||||||
|
}
|
||||||
|
// background
|
||||||
|
SetDrawingMode(B_OP_COPY);
|
||||||
|
FillRect(r, B_SOLID_LOW);
|
||||||
|
ConstrainClippingRegion(NULL);
|
||||||
|
// label
|
||||||
|
if (fLabel.CountChars() > 0) {
|
||||||
|
SetDrawingMode(B_OP_COPY);
|
||||||
|
font_height fh;
|
||||||
|
GetFontHeight(&fh);
|
||||||
|
float y = Bounds().bottom - 4.0;
|
||||||
|
y -= fh.descent;
|
||||||
|
float x = (width - StringWidth(fLabel.String())) / 2.0;
|
||||||
|
DrawString(fLabel.String(), BPoint(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseDown
|
||||||
|
void
|
||||||
|
IconButton::MouseDown(BPoint where)
|
||||||
|
{
|
||||||
|
if (!IsValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_HasFlags(STATE_ENABLED)/* && !_HasFlags(STATE_FORCE_PRESSED)*/) {
|
||||||
|
if (Bounds().Contains(where)) {
|
||||||
|
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
|
||||||
|
_AddFlags(STATE_PRESSED | STATE_TRACKING);
|
||||||
|
} else {
|
||||||
|
_ClearFlags(STATE_PRESSED | STATE_TRACKING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseUp
|
||||||
|
void
|
||||||
|
IconButton::MouseUp(BPoint where)
|
||||||
|
{
|
||||||
|
if (!IsValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// if (!_HasFlags(STATE_FORCE_PRESSED)) {
|
||||||
|
if (_HasFlags(STATE_ENABLED) && _HasFlags(STATE_PRESSED) && Bounds().Contains(where))
|
||||||
|
Invoke();
|
||||||
|
else if (Bounds().Contains(where))
|
||||||
|
_AddFlags(STATE_INSIDE);
|
||||||
|
_ClearFlags(STATE_PRESSED | STATE_TRACKING);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// MouseMoved
|
||||||
|
void
|
||||||
|
IconButton::MouseMoved(BPoint where, uint32 transit, const BMessage* message)
|
||||||
|
{
|
||||||
|
if (!IsValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 buttons = 0;
|
||||||
|
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
||||||
|
// catch a mouse up event that we might have missed
|
||||||
|
if (!buttons && _HasFlags(STATE_PRESSED)) {
|
||||||
|
MouseUp(where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buttons && !_HasFlags(STATE_TRACKING))
|
||||||
|
return;
|
||||||
|
if ((transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW)
|
||||||
|
&& _HasFlags(STATE_ENABLED))
|
||||||
|
_AddFlags(STATE_INSIDE);
|
||||||
|
else
|
||||||
|
_ClearFlags(STATE_INSIDE);
|
||||||
|
if (_HasFlags(STATE_TRACKING)) {
|
||||||
|
if (Bounds().Contains(where))
|
||||||
|
_AddFlags(STATE_PRESSED);
|
||||||
|
else
|
||||||
|
_ClearFlags(STATE_PRESSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MIN_SPACE 15.0
|
||||||
|
|
||||||
|
// GetPreferredSize
|
||||||
|
void
|
||||||
|
IconButton::GetPreferredSize(float* width, float* height)
|
||||||
|
{
|
||||||
|
float minWidth = 0.0;
|
||||||
|
float minHeight = 0.0;
|
||||||
|
if (IsValid()) {
|
||||||
|
minWidth += fNormalBitmap->Bounds().IntegerWidth() + 1.0;
|
||||||
|
minHeight += fNormalBitmap->Bounds().IntegerHeight() + 1.0;
|
||||||
|
}
|
||||||
|
if (minWidth < MIN_SPACE)
|
||||||
|
minWidth = MIN_SPACE;
|
||||||
|
if (minHeight < MIN_SPACE)
|
||||||
|
minHeight = MIN_SPACE;
|
||||||
|
|
||||||
|
float hPadding = max_c(6.0, ceilf(minHeight / 4.0));
|
||||||
|
float vPadding = max_c(6.0, ceilf(minWidth / 4.0));
|
||||||
|
|
||||||
|
if (fLabel.CountChars() > 0) {
|
||||||
|
font_height fh;
|
||||||
|
GetFontHeight(&fh);
|
||||||
|
minHeight += ceilf(fh.ascent + fh.descent) + vPadding;
|
||||||
|
minWidth += StringWidth(fLabel.String()) + vPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width)
|
||||||
|
*width = minWidth + hPadding;
|
||||||
|
if (height)
|
||||||
|
*height = minHeight + vPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinSize
|
||||||
|
BSize
|
||||||
|
IconButton::MinSize()
|
||||||
|
{
|
||||||
|
BSize size;
|
||||||
|
GetPreferredSize(&size.width, &size.height);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaxSize
|
||||||
|
BSize
|
||||||
|
IconButton::MaxSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke
|
||||||
|
status_t
|
||||||
|
IconButton::Invoke(BMessage* message)
|
||||||
|
{
|
||||||
|
if (!message)
|
||||||
|
message = Message();
|
||||||
|
if (message) {
|
||||||
|
BMessage clone(*message);
|
||||||
|
clone.AddInt64("be:when", system_time());
|
||||||
|
clone.AddPointer("be:source", (BView*)this);
|
||||||
|
clone.AddInt32("be:value", Value());
|
||||||
|
clone.AddInt32("id", ID());
|
||||||
|
return BInvoker::Invoke(&clone);
|
||||||
|
}
|
||||||
|
return BInvoker::Invoke(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPressed
|
||||||
|
void
|
||||||
|
IconButton::SetPressed(bool pressed)
|
||||||
|
{
|
||||||
|
if (pressed)
|
||||||
|
_AddFlags(STATE_FORCE_PRESSED);
|
||||||
|
else
|
||||||
|
_ClearFlags(STATE_FORCE_PRESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPressed
|
||||||
|
bool
|
||||||
|
IconButton::IsPressed() const
|
||||||
|
{
|
||||||
|
return _HasFlags(STATE_FORCE_PRESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
IconButton::SetIcon(int32 resourceID)
|
||||||
|
{
|
||||||
|
app_info info;
|
||||||
|
status_t status = be_app->GetAppInfo(&info);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
BResources resources(&info.ref);
|
||||||
|
status = resources.InitCheck();
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
const void* data = resources.LoadResource(B_VECTOR_ICON_TYPE, resourceID,
|
||||||
|
&size);
|
||||||
|
if (data != NULL) {
|
||||||
|
BBitmap bitmap(BRect(0, 0, 31, 31), B_BITMAP_NO_SERVER_LINK, B_RGBA32);
|
||||||
|
status = bitmap.InitCheck();
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
status = BIconUtils::GetVectorIcon(reinterpret_cast<const uint8*>(data),
|
||||||
|
size, &bitmap);
|
||||||
|
if (status != B_OK)
|
||||||
|
return status;
|
||||||
|
return SetIcon(&bitmap);
|
||||||
|
}
|
||||||
|
// const void* data = resources.LoadResource(B_BITMAP_TYPE, resourceID, &size);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIcon
|
||||||
|
status_t
|
||||||
|
IconButton::SetIcon(const char* pathToBitmap)
|
||||||
|
{
|
||||||
|
if (pathToBitmap == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
status_t status = B_BAD_VALUE;
|
||||||
|
BBitmap* fileBitmap = NULL;
|
||||||
|
// try to load bitmap from either relative or absolute path
|
||||||
|
BEntry entry(pathToBitmap, true);
|
||||||
|
if (!entry.Exists()) {
|
||||||
|
app_info info;
|
||||||
|
status = be_app->GetAppInfo(&info);
|
||||||
|
if (status == B_OK) {
|
||||||
|
BEntry app_entry(&info.ref, true);
|
||||||
|
BPath path;
|
||||||
|
app_entry.GetPath(&path);
|
||||||
|
status = path.InitCheck();
|
||||||
|
if (status == B_OK) {
|
||||||
|
status = path.GetParent(&path);
|
||||||
|
if (status == B_OK) {
|
||||||
|
status = path.Append(pathToBitmap, true);
|
||||||
|
if (status == B_OK)
|
||||||
|
fileBitmap = BTranslationUtils::GetBitmap(path.Path());
|
||||||
|
else
|
||||||
|
printf("IconButton::SetIcon() - path.Append() failed: %s\n", strerror(status));
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - path.GetParent() failed: %s\n", strerror(status));
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - path.InitCheck() failed: %s\n", strerror(status));
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - be_app->GetAppInfo() failed: %s\n", strerror(status));
|
||||||
|
} else
|
||||||
|
fileBitmap = BTranslationUtils::GetBitmap(pathToBitmap);
|
||||||
|
if (fileBitmap) {
|
||||||
|
status = _MakeBitmaps(fileBitmap);
|
||||||
|
delete fileBitmap;
|
||||||
|
} else
|
||||||
|
status = B_ERROR;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIcon
|
||||||
|
status_t
|
||||||
|
IconButton::SetIcon(const BBitmap* bitmap)
|
||||||
|
{
|
||||||
|
if (bitmap && bitmap->ColorSpace() == B_CMAP8) {
|
||||||
|
status_t status = bitmap->InitCheck();
|
||||||
|
if (status >= B_OK) {
|
||||||
|
if (BBitmap* rgb32Bitmap = _ConvertToRGB32(bitmap)) {
|
||||||
|
status = _MakeBitmaps(rgb32Bitmap);
|
||||||
|
delete rgb32Bitmap;
|
||||||
|
} else
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
} else
|
||||||
|
return _MakeBitmaps(bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIcon
|
||||||
|
status_t
|
||||||
|
IconButton::SetIcon(const BMimeType* fileType, bool small)
|
||||||
|
{
|
||||||
|
status_t status = fileType ? fileType->InitCheck() : B_BAD_VALUE;
|
||||||
|
if (status >= B_OK) {
|
||||||
|
BBitmap* mimeBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, 15.0, 15.0), B_CMAP8);
|
||||||
|
if (mimeBitmap && mimeBitmap->IsValid()) {
|
||||||
|
status = fileType->GetIcon(mimeBitmap, small ? B_MINI_ICON : B_LARGE_ICON);
|
||||||
|
if (status >= B_OK) {
|
||||||
|
if (BBitmap* bitmap = _ConvertToRGB32(mimeBitmap)) {
|
||||||
|
status = _MakeBitmaps(bitmap);
|
||||||
|
delete bitmap;
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - fileType->GetIcon() failed: %s\n", strerror(status));
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - B_CMAP8 bitmap is not valid\n");
|
||||||
|
delete mimeBitmap;
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - fileType is not valid: %s\n", strerror(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIcon
|
||||||
|
status_t
|
||||||
|
IconButton::SetIcon(const unsigned char* bitsFromQuickRes,
|
||||||
|
uint32 width, uint32 height, color_space format, bool convertToBW)
|
||||||
|
{
|
||||||
|
status_t status = B_BAD_VALUE;
|
||||||
|
if (bitsFromQuickRes && width > 0 && height > 0) {
|
||||||
|
BBitmap* quickResBitmap = new(nothrow) BBitmap(BRect(0.0, 0.0, width - 1.0, height - 1.0), format);
|
||||||
|
status = quickResBitmap ? quickResBitmap->InitCheck() : B_ERROR;
|
||||||
|
if (status >= B_OK) {
|
||||||
|
// It doesn't look right to copy BitsLength() bytes, but bitmaps
|
||||||
|
// exported from QuickRes still contain their padding, so it is alright.
|
||||||
|
memcpy(quickResBitmap->Bits(), bitsFromQuickRes, quickResBitmap->BitsLength());
|
||||||
|
if (format != B_RGB32 && format != B_RGBA32 && format != B_RGB32_BIG && format != B_RGBA32_BIG) {
|
||||||
|
// colorspace needs conversion
|
||||||
|
BBitmap* bitmap = new(nothrow) BBitmap(quickResBitmap->Bounds(), B_RGB32, true);
|
||||||
|
if (bitmap && bitmap->IsValid()) {
|
||||||
|
BView* helper = new BView(bitmap->Bounds(), "helper",
|
||||||
|
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||||
|
if (bitmap->Lock()) {
|
||||||
|
bitmap->AddChild(helper);
|
||||||
|
helper->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
helper->FillRect(helper->Bounds());
|
||||||
|
helper->SetDrawingMode(B_OP_OVER);
|
||||||
|
helper->DrawBitmap(quickResBitmap, BPoint(0.0, 0.0));
|
||||||
|
helper->Sync();
|
||||||
|
bitmap->Unlock();
|
||||||
|
}
|
||||||
|
status = _MakeBitmaps(bitmap);
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - B_RGB32 bitmap is not valid\n");
|
||||||
|
delete bitmap;
|
||||||
|
} else {
|
||||||
|
// native colorspace (32 bits)
|
||||||
|
if (convertToBW) {
|
||||||
|
// convert to gray scale icon
|
||||||
|
uint8* bits = (uint8*)quickResBitmap->Bits();
|
||||||
|
uint32 bpr = quickResBitmap->BytesPerRow();
|
||||||
|
for (uint32 y = 0; y < height; y++) {
|
||||||
|
uint8* handle = bits;
|
||||||
|
uint8 gray;
|
||||||
|
for (uint32 x = 0; x < width; x++) {
|
||||||
|
gray = uint8((116 * handle[0] + 600 * handle[1] + 308 * handle[2]) / 1024);
|
||||||
|
handle[0] = gray;
|
||||||
|
handle[1] = gray;
|
||||||
|
handle[2] = gray;
|
||||||
|
handle += 4;
|
||||||
|
}
|
||||||
|
bits += bpr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status = _MakeBitmaps(quickResBitmap);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("IconButton::SetIcon() - error allocating bitmap: %s\n", strerror(status));
|
||||||
|
delete quickResBitmap;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearIcon
|
||||||
|
void
|
||||||
|
IconButton::ClearIcon()
|
||||||
|
{
|
||||||
|
_DeleteBitmaps();
|
||||||
|
_Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IconButton::TrimIcon(bool keepAspect)
|
||||||
|
{
|
||||||
|
if (fNormalBitmap == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8* bits = (uint8*)fNormalBitmap->Bits();
|
||||||
|
uint32 bpr = fNormalBitmap->BytesPerRow();
|
||||||
|
uint32 width = fNormalBitmap->Bounds().IntegerWidth() + 1;
|
||||||
|
uint32 height = fNormalBitmap->Bounds().IntegerHeight() + 1;
|
||||||
|
BRect trimmed(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
|
||||||
|
for (uint32 y = 0; y < height; y++) {
|
||||||
|
uint8* b = bits + 3;
|
||||||
|
bool rowHasAlpha = false;
|
||||||
|
for (uint32 x = 0; x < width; x++) {
|
||||||
|
if (*b) {
|
||||||
|
rowHasAlpha = true;
|
||||||
|
if (x < trimmed.left)
|
||||||
|
trimmed.left = x;
|
||||||
|
if (x > trimmed.right)
|
||||||
|
trimmed.right = x;
|
||||||
|
}
|
||||||
|
b += 4;
|
||||||
|
}
|
||||||
|
if (rowHasAlpha) {
|
||||||
|
if (y < trimmed.top)
|
||||||
|
trimmed.top = y;
|
||||||
|
if (y > trimmed.bottom)
|
||||||
|
trimmed.bottom = y;
|
||||||
|
}
|
||||||
|
bits += bpr;
|
||||||
|
}
|
||||||
|
if (!trimmed.IsValid())
|
||||||
|
return;
|
||||||
|
if (keepAspect) {
|
||||||
|
float minInset = trimmed.left;
|
||||||
|
minInset = min_c(minInset, trimmed.top);
|
||||||
|
minInset = min_c(minInset, fNormalBitmap->Bounds().right - trimmed.right);
|
||||||
|
minInset = min_c(minInset, fNormalBitmap->Bounds().bottom - trimmed.bottom);
|
||||||
|
trimmed = fNormalBitmap->Bounds().InsetByCopy(minInset, minInset);
|
||||||
|
}
|
||||||
|
trimmed = trimmed & fNormalBitmap->Bounds();
|
||||||
|
BBitmap trimmedBitmap(trimmed.OffsetToCopy(B_ORIGIN),
|
||||||
|
B_BITMAP_NO_SERVER_LINK, B_RGBA32);
|
||||||
|
bits = (uint8*)fNormalBitmap->Bits();
|
||||||
|
bits += 4 * (int32)trimmed.left + bpr * (int32)trimmed.top;
|
||||||
|
uint8* dst = (uint8*)trimmedBitmap.Bits();
|
||||||
|
uint32 trimmedWidth = trimmedBitmap.Bounds().IntegerWidth() + 1;
|
||||||
|
uint32 trimmedHeight = trimmedBitmap.Bounds().IntegerHeight() + 1;
|
||||||
|
uint32 trimmedBPR = trimmedBitmap.BytesPerRow();
|
||||||
|
for (uint32 y = 0; y < trimmedHeight; y++) {
|
||||||
|
memcpy(dst, bits, trimmedWidth * 4);
|
||||||
|
dst += trimmedBPR;
|
||||||
|
bits += bpr;
|
||||||
|
}
|
||||||
|
SetIcon(&trimmedBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitmap
|
||||||
|
BBitmap*
|
||||||
|
IconButton::Bitmap() const
|
||||||
|
{
|
||||||
|
BBitmap* bitmap = NULL;
|
||||||
|
if (fNormalBitmap && fNormalBitmap->IsValid()) {
|
||||||
|
bitmap = new(nothrow) BBitmap(fNormalBitmap);
|
||||||
|
if (bitmap->IsValid()) {
|
||||||
|
// TODO: remove this functionality when we use real transparent bitmaps
|
||||||
|
uint8* bits = (uint8*)bitmap->Bits();
|
||||||
|
uint32 bpr = bitmap->BytesPerRow();
|
||||||
|
uint32 width = bitmap->Bounds().IntegerWidth() + 1;
|
||||||
|
uint32 height = bitmap->Bounds().IntegerHeight() + 1;
|
||||||
|
color_space format = bitmap->ColorSpace();
|
||||||
|
if (format == B_CMAP8) {
|
||||||
|
// replace gray with magic transparent index
|
||||||
|
} else if (format == B_RGB32) {
|
||||||
|
for (uint32 y = 0; y < height; y++) {
|
||||||
|
uint8* bitsHandle = bits;
|
||||||
|
for (uint32 x = 0; x < width; x++) {
|
||||||
|
if (bitsHandle[0] == 216
|
||||||
|
&& bitsHandle[1] == 216
|
||||||
|
&& bitsHandle[2] == 216) {
|
||||||
|
bitsHandle[3] = 0; // make this pixel completely transparent
|
||||||
|
}
|
||||||
|
bitsHandle += 4;
|
||||||
|
}
|
||||||
|
bits += bpr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete bitmap;
|
||||||
|
bitmap = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawBorder
|
||||||
|
bool
|
||||||
|
IconButton::DrawBorder() const
|
||||||
|
{
|
||||||
|
return ((IsEnabled() && (_HasFlags(STATE_INSIDE)
|
||||||
|
|| _HasFlags(STATE_TRACKING))) || _HasFlags(STATE_FORCE_PRESSED));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawNormalBorder
|
||||||
|
void
|
||||||
|
IconButton::DrawNormalBorder(BRect r, rgb_color background,
|
||||||
|
rgb_color shadow, rgb_color darkShadow,
|
||||||
|
rgb_color lightShadow, rgb_color light)
|
||||||
|
{
|
||||||
|
_DrawFrame(r, shadow, darkShadow, light, lightShadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawPressedBorder
|
||||||
|
void
|
||||||
|
IconButton::DrawPressedBorder(BRect r, rgb_color background,
|
||||||
|
rgb_color shadow, rgb_color darkShadow,
|
||||||
|
rgb_color lightShadow, rgb_color light)
|
||||||
|
{
|
||||||
|
_DrawFrame(r, shadow, light, darkShadow, background);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValid
|
||||||
|
bool
|
||||||
|
IconButton::IsValid() const
|
||||||
|
{
|
||||||
|
return (fNormalBitmap && fDisabledBitmap && fClickedBitmap
|
||||||
|
&& fDisabledClickedBitmap
|
||||||
|
&& fNormalBitmap->IsValid()
|
||||||
|
&& fDisabledBitmap->IsValid()
|
||||||
|
&& fClickedBitmap->IsValid()
|
||||||
|
&& fDisabledClickedBitmap->IsValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value
|
||||||
|
int32
|
||||||
|
IconButton::Value() const
|
||||||
|
{
|
||||||
|
return _HasFlags(STATE_PRESSED) ? B_CONTROL_ON : B_CONTROL_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValue
|
||||||
|
void
|
||||||
|
IconButton::SetValue(int32 value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
_AddFlags(STATE_PRESSED);
|
||||||
|
else
|
||||||
|
_ClearFlags(STATE_PRESSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEnabled
|
||||||
|
bool
|
||||||
|
IconButton::IsEnabled() const
|
||||||
|
{
|
||||||
|
return _HasFlags(STATE_ENABLED) ? B_CONTROL_ON : B_CONTROL_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEnabled
|
||||||
|
void
|
||||||
|
IconButton::SetEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
_AddFlags(STATE_ENABLED);
|
||||||
|
else
|
||||||
|
_ClearFlags(STATE_ENABLED | STATE_TRACKING | STATE_INSIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// _ConvertToRGB32
|
||||||
|
BBitmap*
|
||||||
|
IconButton::_ConvertToRGB32(const BBitmap* bitmap) const
|
||||||
|
{
|
||||||
|
BBitmap* convertedBitmap = new(nothrow) BBitmap(bitmap->Bounds(),
|
||||||
|
B_BITMAP_ACCEPTS_VIEWS, B_RGBA32);
|
||||||
|
if (convertedBitmap && convertedBitmap->IsValid()) {
|
||||||
|
memset(convertedBitmap->Bits(), 0, convertedBitmap->BitsLength());
|
||||||
|
BView* helper = new BView(bitmap->Bounds(), "helper",
|
||||||
|
B_FOLLOW_NONE, B_WILL_DRAW);
|
||||||
|
if (convertedBitmap->Lock()) {
|
||||||
|
convertedBitmap->AddChild(helper);
|
||||||
|
helper->SetDrawingMode(B_OP_OVER);
|
||||||
|
helper->DrawBitmap(bitmap, BPoint(0.0, 0.0));
|
||||||
|
helper->Sync();
|
||||||
|
convertedBitmap->Unlock();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete convertedBitmap;
|
||||||
|
convertedBitmap = NULL;
|
||||||
|
}
|
||||||
|
return convertedBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _MakeBitmaps
|
||||||
|
status_t
|
||||||
|
IconButton::_MakeBitmaps(const BBitmap* bitmap)
|
||||||
|
{
|
||||||
|
status_t status = bitmap ? bitmap->InitCheck() : B_BAD_VALUE;
|
||||||
|
if (status >= B_OK) {
|
||||||
|
// make our own versions of the bitmap
|
||||||
|
BRect b(bitmap->Bounds());
|
||||||
|
_DeleteBitmaps();
|
||||||
|
color_space format = bitmap->ColorSpace();
|
||||||
|
fNormalBitmap = new(nothrow) BBitmap(b, format);
|
||||||
|
fDisabledBitmap = new(nothrow) BBitmap(b, format);
|
||||||
|
fClickedBitmap = new(nothrow) BBitmap(b, format);
|
||||||
|
fDisabledClickedBitmap = new(nothrow) BBitmap(b, format);
|
||||||
|
if (IsValid()) {
|
||||||
|
// copy bitmaps from file bitmap
|
||||||
|
uint8* nBits = (uint8*)fNormalBitmap->Bits();
|
||||||
|
uint8* dBits = (uint8*)fDisabledBitmap->Bits();
|
||||||
|
uint8* cBits = (uint8*)fClickedBitmap->Bits();
|
||||||
|
uint8* dcBits = (uint8*)fDisabledClickedBitmap->Bits();
|
||||||
|
uint8* fBits = (uint8*)bitmap->Bits();
|
||||||
|
int32 nbpr = fNormalBitmap->BytesPerRow();
|
||||||
|
int32 fbpr = bitmap->BytesPerRow();
|
||||||
|
int32 pixels = b.IntegerWidth() + 1;
|
||||||
|
int32 lines = b.IntegerHeight() + 1;
|
||||||
|
// nontransparent version:
|
||||||
|
if (format == B_RGB32 || format == B_RGB32_BIG) {
|
||||||
|
// iterate over color components
|
||||||
|
for (int32 y = 0; y < lines; y++) {
|
||||||
|
for (int32 x = 0; x < pixels; x++) {
|
||||||
|
int32 nOffset = 4 * x;
|
||||||
|
int32 fOffset = 4 * x;
|
||||||
|
nBits[nOffset + 0] = fBits[fOffset + 0];
|
||||||
|
nBits[nOffset + 1] = fBits[fOffset + 1];
|
||||||
|
nBits[nOffset + 2] = fBits[fOffset + 2];
|
||||||
|
nBits[nOffset + 3] = 255;
|
||||||
|
// clicked bits are darker (lame method...)
|
||||||
|
cBits[nOffset + 0] = (uint8)((float)nBits[nOffset + 0] * 0.8);
|
||||||
|
cBits[nOffset + 1] = (uint8)((float)nBits[nOffset + 1] * 0.8);
|
||||||
|
cBits[nOffset + 2] = (uint8)((float)nBits[nOffset + 2] * 0.8);
|
||||||
|
cBits[nOffset + 3] = 255;
|
||||||
|
// disabled bits have less contrast (lame method...)
|
||||||
|
uint8 grey = 216;
|
||||||
|
float dist = (nBits[nOffset + 0] - grey) * 0.4;
|
||||||
|
dBits[nOffset + 0] = (uint8)(grey + dist);
|
||||||
|
dist = (nBits[nOffset + 1] - grey) * 0.4;
|
||||||
|
dBits[nOffset + 1] = (uint8)(grey + dist);
|
||||||
|
dist = (nBits[nOffset + 2] - grey) * 0.4;
|
||||||
|
dBits[nOffset + 2] = (uint8)(grey + dist);
|
||||||
|
dBits[nOffset + 3] = 255;
|
||||||
|
// disabled bits have less contrast (lame method...)
|
||||||
|
grey = 188;
|
||||||
|
dist = (nBits[nOffset + 0] - grey) * 0.4;
|
||||||
|
dcBits[nOffset + 0] = (uint8)(grey + dist);
|
||||||
|
dist = (nBits[nOffset + 1] - grey) * 0.4;
|
||||||
|
dcBits[nOffset + 1] = (uint8)(grey + dist);
|
||||||
|
dist = (nBits[nOffset + 2] - grey) * 0.4;
|
||||||
|
dcBits[nOffset + 2] = (uint8)(grey + dist);
|
||||||
|
dcBits[nOffset + 3] = 255;
|
||||||
|
}
|
||||||
|
nBits += nbpr;
|
||||||
|
dBits += nbpr;
|
||||||
|
cBits += nbpr;
|
||||||
|
dcBits += nbpr;
|
||||||
|
fBits += fbpr;
|
||||||
|
}
|
||||||
|
// transparent version:
|
||||||
|
} else if (format == B_RGBA32 || format == B_RGBA32_BIG) {
|
||||||
|
// iterate over color components
|
||||||
|
for (int32 y = 0; y < lines; y++) {
|
||||||
|
for (int32 x = 0; x < pixels; x++) {
|
||||||
|
int32 nOffset = 4 * x;
|
||||||
|
int32 fOffset = 4 * x;
|
||||||
|
nBits[nOffset + 0] = fBits[fOffset + 0];
|
||||||
|
nBits[nOffset + 1] = fBits[fOffset + 1];
|
||||||
|
nBits[nOffset + 2] = fBits[fOffset + 2];
|
||||||
|
nBits[nOffset + 3] = fBits[fOffset + 3];
|
||||||
|
// clicked bits are darker (lame method...)
|
||||||
|
cBits[nOffset + 0] = (uint8)(nBits[nOffset + 0] * 0.8);
|
||||||
|
cBits[nOffset + 1] = (uint8)(nBits[nOffset + 1] * 0.8);
|
||||||
|
cBits[nOffset + 2] = (uint8)(nBits[nOffset + 2] * 0.8);
|
||||||
|
cBits[nOffset + 3] = fBits[fOffset + 3];
|
||||||
|
// disabled bits have less opacity
|
||||||
|
|
||||||
|
uint8 grey = ((uint16)nBits[nOffset + 0] * 10
|
||||||
|
+ nBits[nOffset + 1] * 60
|
||||||
|
+ nBits[nOffset + 2] * 30) / 100;
|
||||||
|
float dist = (nBits[nOffset + 0] - grey) * 0.3;
|
||||||
|
dBits[nOffset + 0] = (uint8)(grey + dist);
|
||||||
|
dist = (nBits[nOffset + 1] - grey) * 0.3;
|
||||||
|
dBits[nOffset + 1] = (uint8)(grey + dist);
|
||||||
|
dist = (nBits[nOffset + 2] - grey) * 0.3;
|
||||||
|
dBits[nOffset + 2] = (uint8)(grey + dist);
|
||||||
|
dBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3);
|
||||||
|
// disabled bits have less contrast (lame method...)
|
||||||
|
dcBits[nOffset + 0] = (uint8)(dBits[nOffset + 0] * 0.8);
|
||||||
|
dcBits[nOffset + 1] = (uint8)(dBits[nOffset + 1] * 0.8);
|
||||||
|
dcBits[nOffset + 2] = (uint8)(dBits[nOffset + 2] * 0.8);
|
||||||
|
dcBits[nOffset + 3] = (uint8)(fBits[fOffset + 3] * 0.3);
|
||||||
|
}
|
||||||
|
nBits += nbpr;
|
||||||
|
dBits += nbpr;
|
||||||
|
cBits += nbpr;
|
||||||
|
dcBits += nbpr;
|
||||||
|
fBits += fbpr;
|
||||||
|
}
|
||||||
|
// unsupported format
|
||||||
|
} else {
|
||||||
|
printf("IconButton::_MakeBitmaps() - bitmap has unsupported colorspace\n");
|
||||||
|
status = B_MISMATCHED_VALUES;
|
||||||
|
_DeleteBitmaps();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("IconButton::_MakeBitmaps() - error allocating local bitmaps\n");
|
||||||
|
status = B_NO_MEMORY;
|
||||||
|
_DeleteBitmaps();
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
printf("IconButton::_MakeBitmaps() - bitmap is not valid\n");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _DeleteBitmaps
|
||||||
|
void
|
||||||
|
IconButton::_DeleteBitmaps()
|
||||||
|
{
|
||||||
|
delete fNormalBitmap;
|
||||||
|
fNormalBitmap = NULL;
|
||||||
|
delete fDisabledBitmap;
|
||||||
|
fDisabledBitmap = NULL;
|
||||||
|
delete fClickedBitmap;
|
||||||
|
fClickedBitmap = NULL;
|
||||||
|
delete fDisabledClickedBitmap;
|
||||||
|
fDisabledClickedBitmap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _Update
|
||||||
|
void
|
||||||
|
IconButton::_Update()
|
||||||
|
{
|
||||||
|
if (LockLooper()) {
|
||||||
|
Invalidate();
|
||||||
|
UnlockLooper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _AddFlags
|
||||||
|
void
|
||||||
|
IconButton::_AddFlags(uint32 flags)
|
||||||
|
{
|
||||||
|
if (!(fButtonState & flags)) {
|
||||||
|
fButtonState |= flags;
|
||||||
|
_Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _ClearFlags
|
||||||
|
void
|
||||||
|
IconButton::_ClearFlags(uint32 flags)
|
||||||
|
{
|
||||||
|
if (fButtonState & flags) {
|
||||||
|
fButtonState &= ~flags;
|
||||||
|
_Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// _HasFlags
|
||||||
|
bool
|
||||||
|
IconButton::_HasFlags(uint32 flags) const
|
||||||
|
{
|
||||||
|
return (fButtonState & flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// _DrawFrame
|
||||||
|
void
|
||||||
|
IconButton::_DrawFrame(BRect r, rgb_color col1, rgb_color col2,
|
||||||
|
rgb_color col3, rgb_color col4)
|
||||||
|
{
|
||||||
|
BeginLineArray(8);
|
||||||
|
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col1);
|
||||||
|
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col1);
|
||||||
|
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col2);
|
||||||
|
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col2);
|
||||||
|
r.InsetBy(1.0, 1.0);
|
||||||
|
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), col3);
|
||||||
|
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), col3);
|
||||||
|
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), col4);
|
||||||
|
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), col4);
|
||||||
|
EndLineArray();
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2010, Haiku.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** gui class that loads an image from disk and shows it
|
||||||
|
as clickable button */
|
||||||
|
|
||||||
|
// TODO: inherit from BControl?
|
||||||
|
|
||||||
|
// NOTE: this file is a duplicate of the version in Icon-O-Matic/generic
|
||||||
|
// it should be placed into a common folder for generic useful stuff
|
||||||
|
|
||||||
|
#ifndef ICON_BUTTON_H
|
||||||
|
#define ICON_BUTTON_H
|
||||||
|
|
||||||
|
#include <Invoker.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
class BBitmap;
|
||||||
|
class BMimeType;
|
||||||
|
|
||||||
|
class IconButton : public BView, public BInvoker {
|
||||||
|
public:
|
||||||
|
IconButton(const char* name,
|
||||||
|
uint32 id,
|
||||||
|
const char* label = NULL,
|
||||||
|
BMessage* message = NULL,
|
||||||
|
BHandler* target = NULL);
|
||||||
|
virtual ~IconButton();
|
||||||
|
|
||||||
|
// BView interface
|
||||||
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
virtual void MouseDown(BPoint where);
|
||||||
|
virtual void MouseUp(BPoint where);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message);
|
||||||
|
virtual void GetPreferredSize(float* width,
|
||||||
|
float* height);
|
||||||
|
virtual BSize MinSize();
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
|
||||||
|
|
||||||
|
// BInvoker interface
|
||||||
|
virtual status_t Invoke(BMessage* message = NULL);
|
||||||
|
|
||||||
|
// IconButton
|
||||||
|
bool IsValid() const;
|
||||||
|
|
||||||
|
virtual int32 Value() const;
|
||||||
|
virtual void SetValue(int32 value);
|
||||||
|
|
||||||
|
bool IsEnabled() const;
|
||||||
|
void SetEnabled(bool enable);
|
||||||
|
|
||||||
|
void SetPressed(bool pressed);
|
||||||
|
bool IsPressed() const;
|
||||||
|
uint32 ID() const
|
||||||
|
{ return fID; }
|
||||||
|
|
||||||
|
status_t SetIcon(int32 resourceID);
|
||||||
|
status_t SetIcon(const char* pathToBitmap);
|
||||||
|
status_t SetIcon(const BBitmap* bitmap);
|
||||||
|
status_t SetIcon(const BMimeType* fileType,
|
||||||
|
bool small = true);
|
||||||
|
status_t SetIcon(const unsigned char* bitsFromQuickRes,
|
||||||
|
uint32 width, uint32 height,
|
||||||
|
color_space format,
|
||||||
|
bool convertToBW = false);
|
||||||
|
void ClearIcon();
|
||||||
|
void TrimIcon(bool keepAspect = true);
|
||||||
|
|
||||||
|
BBitmap* Bitmap() const;
|
||||||
|
// caller has to delete the returned bitmap
|
||||||
|
|
||||||
|
virtual bool DrawBorder() const;
|
||||||
|
virtual void DrawNormalBorder(BRect r,
|
||||||
|
rgb_color background,
|
||||||
|
rgb_color shadow,
|
||||||
|
rgb_color darkShadow,
|
||||||
|
rgb_color lightShadow,
|
||||||
|
rgb_color light);
|
||||||
|
virtual void DrawPressedBorder(BRect r,
|
||||||
|
rgb_color background,
|
||||||
|
rgb_color shadow,
|
||||||
|
rgb_color darkShadow,
|
||||||
|
rgb_color lightShadow,
|
||||||
|
rgb_color light);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum {
|
||||||
|
STATE_NONE = 0x0000,
|
||||||
|
STATE_TRACKING = 0x0001,
|
||||||
|
STATE_PRESSED = 0x0002,
|
||||||
|
STATE_ENABLED = 0x0004,
|
||||||
|
STATE_INSIDE = 0x0008,
|
||||||
|
STATE_FORCE_PRESSED = 0x0010,
|
||||||
|
};
|
||||||
|
|
||||||
|
void _AddFlags(uint32 flags);
|
||||||
|
void _ClearFlags(uint32 flags);
|
||||||
|
bool _HasFlags(uint32 flags) const;
|
||||||
|
|
||||||
|
void _DrawFrame(BRect frame,
|
||||||
|
rgb_color col1,
|
||||||
|
rgb_color col2,
|
||||||
|
rgb_color col3,
|
||||||
|
rgb_color col4);
|
||||||
|
|
||||||
|
// private:
|
||||||
|
BBitmap* _ConvertToRGB32(const BBitmap* bitmap) const;
|
||||||
|
status_t _MakeBitmaps(const BBitmap* bitmap);
|
||||||
|
void _DeleteBitmaps();
|
||||||
|
void _SendMessage() const;
|
||||||
|
void _Update();
|
||||||
|
|
||||||
|
uint32 fButtonState;
|
||||||
|
int32 fID;
|
||||||
|
BBitmap* fNormalBitmap;
|
||||||
|
BBitmap* fDisabledBitmap;
|
||||||
|
BBitmap* fClickedBitmap;
|
||||||
|
BBitmap* fDisabledClickedBitmap;
|
||||||
|
BString fLabel;
|
||||||
|
|
||||||
|
BHandler* fTargetCache;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ICON_BUTTON_H
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2008, Haiku. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _ICON_UTILS_H
|
||||||
|
#define _ICON_UTILS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Mime.h>
|
||||||
|
|
||||||
|
class BBitmap;
|
||||||
|
class BNode;
|
||||||
|
|
||||||
|
|
||||||
|
// This class is a little different from many other classes.
|
||||||
|
// You don't create an instance of it; you just call its various
|
||||||
|
// static member functions for utility-like operations.
|
||||||
|
class BIconUtils {
|
||||||
|
BIconUtils();
|
||||||
|
~BIconUtils();
|
||||||
|
BIconUtils(const BIconUtils&);
|
||||||
|
BIconUtils& operator=(const BIconUtils&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Utility function to import an icon from the node that
|
||||||
|
// has either of the provided attribute names. Which icon type
|
||||||
|
// is preferred (vector, small or large B_CMAP8 icon) depends
|
||||||
|
// on the colorspace of the provided bitmap. If the colorspace
|
||||||
|
// is B_CMAP8, B_CMAP8 icons are preferred. In that case, the
|
||||||
|
// bitmap size must also match the provided icon_size "size"!
|
||||||
|
static status_t GetIcon(BNode* node,
|
||||||
|
const char* vectorIconAttrName,
|
||||||
|
const char* smallIconAttrName,
|
||||||
|
const char* largeIconAttrName,
|
||||||
|
icon_size size, BBitmap* result);
|
||||||
|
|
||||||
|
// Utility functions to import a vector icon in "flat icon"
|
||||||
|
// format from a BNode attribute or from a flat buffer in
|
||||||
|
// memory into the preallocated BBitmap "result".
|
||||||
|
// The colorspace of result needs to be B_RGBA32 or at
|
||||||
|
// least B_RGB32 (though that makes less sense). The icon
|
||||||
|
// will be scaled from it's "native" size of 64x64 to the
|
||||||
|
// size of the bitmap, the scale is derived from the bitmap
|
||||||
|
// width, the bitmap should have square dimension, or the
|
||||||
|
// icon will be cut off at the bottom (or have room left).
|
||||||
|
static status_t GetVectorIcon(BNode* node,
|
||||||
|
const char* attrName, BBitmap* result);
|
||||||
|
|
||||||
|
static status_t GetVectorIcon(const uint8* buffer,
|
||||||
|
size_t size, BBitmap* result);
|
||||||
|
|
||||||
|
// Utility function to import an "old" BeOS icon in B_CMAP8
|
||||||
|
// colorspace from either the small icon attribute or the
|
||||||
|
// large icon attribute as given in "smallIconAttrName" and
|
||||||
|
// "largeIconAttrName". Which icon is loaded depends on
|
||||||
|
// the given "size".
|
||||||
|
static status_t GetCMAP8Icon(BNode* node,
|
||||||
|
const char* smallIconAttrName,
|
||||||
|
const char* largeIconAttrName,
|
||||||
|
icon_size size, BBitmap* icon);
|
||||||
|
|
||||||
|
// Utility functions to convert from old icon colorspace
|
||||||
|
// into colorspace of BBitmap "result" (should be B_RGBA32
|
||||||
|
// to make any sense).
|
||||||
|
static status_t ConvertFromCMAP8(BBitmap* source,
|
||||||
|
BBitmap* result);
|
||||||
|
static status_t ConvertToCMAP8(BBitmap* source,
|
||||||
|
BBitmap* result);
|
||||||
|
|
||||||
|
static status_t ConvertFromCMAP8(const uint8* data,
|
||||||
|
uint32 width, uint32 height,
|
||||||
|
uint32 bytesPerRow, BBitmap* result);
|
||||||
|
|
||||||
|
static status_t ConvertToCMAP8(const uint8* data,
|
||||||
|
uint32 width, uint32 height,
|
||||||
|
uint32 bytesPerRow, BBitmap* result);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _ICON_UTILS_H
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
Open Tracker License
|
||||||
|
|
||||||
|
Terms and Conditions
|
||||||
|
|
||||||
|
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice applies to all licensees
|
||||||
|
and shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||||
|
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
|
this Software without prior written authorization from Be Incorporated.
|
||||||
|
|
||||||
|
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||||
|
of Be Incorporated in the United States and other countries. Other brand product
|
||||||
|
names are registered trademarks or trademarks of their respective holders.
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// NavMenu is a hierarchical menu of volumes, folders, files and queries
|
||||||
|
// displays icons, uses the SlowMenu API for full interruptability
|
||||||
|
|
||||||
|
#ifndef NAV_MENU_H
|
||||||
|
#define NAV_MENU_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <StorageDefs.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
|
||||||
|
#include "SlowMenu.h"
|
||||||
|
|
||||||
|
|
||||||
|
template<class T> class BObjectList;
|
||||||
|
class BMenuItem;
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
class Model;
|
||||||
|
class BContainerWindow;
|
||||||
|
class ModelMenuItem;
|
||||||
|
class EntryListBase;
|
||||||
|
|
||||||
|
|
||||||
|
class TrackingHookData {
|
||||||
|
public:
|
||||||
|
TrackingHookData()
|
||||||
|
:
|
||||||
|
fTrackingHook(NULL),
|
||||||
|
fDragMessage(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool (*fTrackingHook)(BMenu *, void *);
|
||||||
|
BMessenger fTarget;
|
||||||
|
const BMessage *fDragMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BNavMenu : public BSlowMenu {
|
||||||
|
public:
|
||||||
|
BNavMenu(const char* title, uint32 message, const BHandler *,
|
||||||
|
BWindow *parentWindow = NULL, const BObjectList<BString> *list = NULL);
|
||||||
|
BNavMenu(const char* title, uint32 message, const BMessenger &,
|
||||||
|
BWindow *parentWindow = NULL, const BObjectList<BString> *list = NULL);
|
||||||
|
// parentWindow, if specified, will be closed if nav menu item invoked
|
||||||
|
// with option held down
|
||||||
|
|
||||||
|
virtual ~BNavMenu();
|
||||||
|
|
||||||
|
virtual void AttachedToWindow();
|
||||||
|
virtual void DetachedFromWindow();
|
||||||
|
|
||||||
|
void SetNavDir(const entry_ref *);
|
||||||
|
void ForceRebuild();
|
||||||
|
bool NeedsToRebuild() const;
|
||||||
|
// will cause menu to get rebuilt next time it is shown
|
||||||
|
|
||||||
|
virtual void ResetTargets();
|
||||||
|
void SetTarget(const BMessenger &);
|
||||||
|
BMessenger Target();
|
||||||
|
|
||||||
|
void SetTypesList(const BObjectList<BString> *list);
|
||||||
|
const BObjectList<BString> *TypesList() const;
|
||||||
|
|
||||||
|
void AddNavDir(const Model *model, uint32 what, BHandler *target,
|
||||||
|
bool populateSubmenu);
|
||||||
|
|
||||||
|
void AddNavParentDir(const char *name, const Model *model, uint32 what, BHandler *target);
|
||||||
|
void AddNavParentDir(const Model *model, uint32 what, BHandler *target);
|
||||||
|
void SetShowParent(bool show);
|
||||||
|
|
||||||
|
static int32 GetMaxMenuWidth();
|
||||||
|
|
||||||
|
static int CompareFolderNamesFirstOne(const BMenuItem *, const BMenuItem *);
|
||||||
|
static int CompareOne(const BMenuItem *, const BMenuItem *);
|
||||||
|
|
||||||
|
static ModelMenuItem *NewModelItem(Model *, const BMessage *, const BMessenger &,
|
||||||
|
bool suppressFolderHierarchy=false, BContainerWindow * = NULL,
|
||||||
|
const BObjectList<BString> *typeslist = NULL,
|
||||||
|
TrackingHookData *hook = NULL);
|
||||||
|
|
||||||
|
TrackingHookData *InitTrackingHook(bool (*hookfunction)(BMenu *, void *),
|
||||||
|
const BMessenger *target, const BMessage *dragMessage);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool StartBuildingItemList();
|
||||||
|
virtual bool AddNextItem();
|
||||||
|
virtual void DoneBuildingItemList();
|
||||||
|
virtual void ClearMenuBuildingState();
|
||||||
|
|
||||||
|
void BuildVolumeMenu();
|
||||||
|
|
||||||
|
void AddOneItem(Model *);
|
||||||
|
void AddRootItemsIfNeeded();
|
||||||
|
void AddTrashItem();
|
||||||
|
static void SetTrackingHookDeep(BMenu *, bool (*)(BMenu *, void *), void *);
|
||||||
|
|
||||||
|
entry_ref fNavDir;
|
||||||
|
BMessage fMessage;
|
||||||
|
BMessenger fMessenger;
|
||||||
|
BWindow *fParentWindow;
|
||||||
|
|
||||||
|
// menu building state
|
||||||
|
uint8 fFlags;
|
||||||
|
BObjectList<BMenuItem> *fItemList;
|
||||||
|
EntryListBase *fContainer;
|
||||||
|
bool fIteratingDesktop;
|
||||||
|
|
||||||
|
const BObjectList<BString> *fTypesList;
|
||||||
|
|
||||||
|
TrackingHookData fTrackingHook;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Spring Loaded Folder convenience routines
|
||||||
|
// used in both Tracker and Deskbar
|
||||||
|
#ifndef _IMPEXP_TRACKER
|
||||||
|
# define _IMPEXP_TRACKER
|
||||||
|
#endif
|
||||||
|
_IMPEXP_TRACKER bool SpringLoadedFolderCompareMessages(const BMessage *incoming,
|
||||||
|
const BMessage *dragmessage);
|
||||||
|
_IMPEXP_TRACKER void SpringLoadedFolderSetMenuStates(const BMenu *menu,
|
||||||
|
const BObjectList<BString> *typeslist);
|
||||||
|
_IMPEXP_TRACKER void SpringLoadedFolderAddUniqueTypeToList(entry_ref *ref,
|
||||||
|
BObjectList<BString> *typeslist);
|
||||||
|
_IMPEXP_TRACKER void SpringLoadedFolderCacheDragData(const BMessage *incoming,
|
||||||
|
BMessage **, BObjectList<BString> **typeslist);
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
#endif // NAV_MENU_H
|
||||||
@@ -0,0 +1,514 @@
|
|||||||
|
/*
|
||||||
|
Open Tracker License
|
||||||
|
|
||||||
|
Terms and Conditions
|
||||||
|
|
||||||
|
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice applies to all licensees
|
||||||
|
and shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||||
|
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
|
this Software without prior written authorization from Be Incorporated.
|
||||||
|
|
||||||
|
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||||
|
of Be Incorporated in the United States and other countries. Other brand product
|
||||||
|
names are registered trademarks or trademarks of their respective holders.
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// bonefish:
|
||||||
|
// * removed need for exceptions
|
||||||
|
// * fixed warnings
|
||||||
|
// * implemented rehashing
|
||||||
|
// * added RemoveAll()
|
||||||
|
// TODO:
|
||||||
|
// * shrinking of element vectors
|
||||||
|
|
||||||
|
// Hash table with open addresssing
|
||||||
|
|
||||||
|
#ifndef __OPEN_HASH_TABLE__
|
||||||
|
#define __OPEN_HASH_TABLE__
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
// don't include <Debug.h>
|
||||||
|
#ifndef ASSERT
|
||||||
|
# define ASSERT(E) (void)0
|
||||||
|
#endif
|
||||||
|
#ifndef TRESPASS
|
||||||
|
# define TRESPASS() (void)0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
template <class Element>
|
||||||
|
class ElementVector {
|
||||||
|
// element vector for OpenHashTable needs to implement this
|
||||||
|
// interface
|
||||||
|
public:
|
||||||
|
Element &At(int32 index);
|
||||||
|
Element *Add();
|
||||||
|
int32 IndexOf(const Element &) const;
|
||||||
|
void Remove(int32 index);
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenHashElement {
|
||||||
|
public:
|
||||||
|
uint32 Hash() const;
|
||||||
|
bool operator==(const OpenHashElement &) const;
|
||||||
|
void Adopt(OpenHashElement &);
|
||||||
|
// low overhead copy, original element is in undefined state
|
||||||
|
// after call (calls Adopt on BString members, etc.)
|
||||||
|
int32 fNext;
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32 kPrimes [] = {
|
||||||
|
509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139,
|
||||||
|
524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859,
|
||||||
|
134217689, 268435399, 536870909, 1073741789, 2147483647, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Element, class ElementVec = ElementVector<Element> >
|
||||||
|
class OpenHashTable {
|
||||||
|
public:
|
||||||
|
OpenHashTable(int32 minSize, ElementVec *elementVector = 0,
|
||||||
|
float maxLoadFactor = 0.8);
|
||||||
|
// it is up to the subclass of OpenHashTable to supply
|
||||||
|
// elementVector
|
||||||
|
~OpenHashTable();
|
||||||
|
|
||||||
|
bool InitCheck() const;
|
||||||
|
|
||||||
|
void SetElementVector(ElementVec *elementVector);
|
||||||
|
|
||||||
|
Element *FindFirst(uint32 elementHash) const;
|
||||||
|
Element *Add(uint32 elementHash);
|
||||||
|
|
||||||
|
void Remove(Element *element, bool dontRehash = false);
|
||||||
|
void RemoveAll();
|
||||||
|
|
||||||
|
// when calling Add, any outstanding element pointer may become
|
||||||
|
// invalid; to deal with this, get the element index and restore
|
||||||
|
// it after the add
|
||||||
|
int32 ElementIndex(const Element *) const;
|
||||||
|
Element *ElementAt(int32 index) const;
|
||||||
|
|
||||||
|
int32 ArraySize() const;
|
||||||
|
int32 VectorSize() const;
|
||||||
|
int32 CountElements() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static int32 OptimalSize(int32 minSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _RehashIfNeeded();
|
||||||
|
bool _Rehash();
|
||||||
|
|
||||||
|
int32 fArraySize;
|
||||||
|
int32 fInitialSize;
|
||||||
|
int32 fElementCount;
|
||||||
|
int32 *fHashArray;
|
||||||
|
ElementVec *fElementVector;
|
||||||
|
float fMaxLoadFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Element>
|
||||||
|
class OpenHashElementArray : public ElementVector<Element> {
|
||||||
|
// this is a straightforward implementation of an element vector
|
||||||
|
// deleting is handled by linking deleted elements into a free list
|
||||||
|
// the vector never shrinks
|
||||||
|
public:
|
||||||
|
OpenHashElementArray(int32 initialSize);
|
||||||
|
~OpenHashElementArray();
|
||||||
|
|
||||||
|
bool InitCheck() const;
|
||||||
|
|
||||||
|
Element &At(int32 index);
|
||||||
|
const Element &At(int32 index) const;
|
||||||
|
Element *Add(const Element &);
|
||||||
|
Element *Add();
|
||||||
|
void Remove(int32 index);
|
||||||
|
int32 IndexOf(const Element &) const;
|
||||||
|
int32 Size() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Element *fData;
|
||||||
|
int32 fSize;
|
||||||
|
int32 fNextFree;
|
||||||
|
int32 fNextDeleted;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
OpenHashTable<Element, ElementVec>::OpenHashTable(int32 minSize,
|
||||||
|
ElementVec *elementVector, float maxLoadFactor)
|
||||||
|
: fArraySize(OptimalSize(minSize)),
|
||||||
|
fInitialSize(fArraySize),
|
||||||
|
fElementCount(0),
|
||||||
|
fElementVector(elementVector),
|
||||||
|
fMaxLoadFactor(maxLoadFactor)
|
||||||
|
{
|
||||||
|
// sanity check the maximal load factor
|
||||||
|
if (fMaxLoadFactor < 0.5)
|
||||||
|
fMaxLoadFactor = 0.5;
|
||||||
|
// allocate and init the array
|
||||||
|
fHashArray = (int32*)calloc(fArraySize, sizeof(int32));
|
||||||
|
if (fHashArray) {
|
||||||
|
for (int32 index = 0; index < fArraySize; index++)
|
||||||
|
fHashArray[index] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
OpenHashTable<Element, ElementVec>::~OpenHashTable()
|
||||||
|
{
|
||||||
|
RemoveAll();
|
||||||
|
free(fHashArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
bool
|
||||||
|
OpenHashTable<Element, ElementVec>::InitCheck() const
|
||||||
|
{
|
||||||
|
return (fHashArray && fElementVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
int32
|
||||||
|
OpenHashTable<Element, ElementVec>::OptimalSize(int32 minSize)
|
||||||
|
{
|
||||||
|
for (int32 index = 0; ; index++)
|
||||||
|
if (!kPrimes[index] || kPrimes[index] >= (uint32)minSize)
|
||||||
|
return (int32)kPrimes[index];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
Element *
|
||||||
|
OpenHashTable<Element, ElementVec>::FindFirst(uint32 hash) const
|
||||||
|
{
|
||||||
|
ASSERT(fElementVector);
|
||||||
|
hash %= fArraySize;
|
||||||
|
if (fHashArray[hash] < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return &fElementVector->At(fHashArray[hash]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
int32
|
||||||
|
OpenHashTable<Element, ElementVec>::ElementIndex(const Element *element) const
|
||||||
|
{
|
||||||
|
return fElementVector->IndexOf(*element);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
Element *
|
||||||
|
OpenHashTable<Element, ElementVec>::ElementAt(int32 index) const
|
||||||
|
{
|
||||||
|
return &fElementVector->At(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
int32
|
||||||
|
OpenHashTable<Element, ElementVec>::ArraySize() const
|
||||||
|
{
|
||||||
|
return fArraySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
int32
|
||||||
|
OpenHashTable<Element, ElementVec>::VectorSize() const
|
||||||
|
{
|
||||||
|
return fElementVector->Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
int32
|
||||||
|
OpenHashTable<Element, ElementVec>::CountElements() const
|
||||||
|
{
|
||||||
|
return fElementCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
Element *
|
||||||
|
OpenHashTable<Element, ElementVec>::Add(uint32 hash)
|
||||||
|
{
|
||||||
|
ASSERT(fElementVector);
|
||||||
|
_RehashIfNeeded();
|
||||||
|
hash %= fArraySize;
|
||||||
|
Element *result = fElementVector->Add();
|
||||||
|
if (result) {
|
||||||
|
result->fNext = fHashArray[hash];
|
||||||
|
fHashArray[hash] = fElementVector->IndexOf(*result);
|
||||||
|
fElementCount++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
void
|
||||||
|
OpenHashTable<Element, ElementVec>::Remove(Element *element, bool dontRehash)
|
||||||
|
{
|
||||||
|
if (!dontRehash)
|
||||||
|
_RehashIfNeeded();
|
||||||
|
uint32 hash = element->Hash() % fArraySize;
|
||||||
|
int32 next = fHashArray[hash];
|
||||||
|
ASSERT(next >= 0);
|
||||||
|
|
||||||
|
if (&fElementVector->At(next) == element) {
|
||||||
|
fHashArray[hash] = element->fNext;
|
||||||
|
fElementVector->Remove(next);
|
||||||
|
fElementCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32 index = next; index >= 0; ) {
|
||||||
|
// look for an existing match in table
|
||||||
|
next = fElementVector->At(index).fNext;
|
||||||
|
if (next < 0) {
|
||||||
|
TRESPASS();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (&fElementVector->At(next) == element) {
|
||||||
|
fElementVector->At(index).fNext = element->fNext;
|
||||||
|
fElementVector->Remove(next);
|
||||||
|
fElementCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
index = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
void
|
||||||
|
OpenHashTable<Element, ElementVec>::RemoveAll()
|
||||||
|
{
|
||||||
|
for (int32 i = 0; fElementCount > 0 && i < fArraySize; i++) {
|
||||||
|
int32 index = fHashArray[i];
|
||||||
|
while (index >= 0) {
|
||||||
|
Element* element = &fElementVector->At(index);
|
||||||
|
int32 next = element->fNext;
|
||||||
|
fElementVector->Remove(index);
|
||||||
|
fElementCount--;
|
||||||
|
index = next;
|
||||||
|
}
|
||||||
|
fHashArray[i] = -1;
|
||||||
|
}
|
||||||
|
_RehashIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
void
|
||||||
|
OpenHashTable<Element, ElementVec>::SetElementVector(ElementVec *elementVector)
|
||||||
|
{
|
||||||
|
fElementVector = elementVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _RehashIfNeeded
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
bool
|
||||||
|
OpenHashTable<Element, ElementVec>::_RehashIfNeeded()
|
||||||
|
{
|
||||||
|
// The load factor range [fMaxLoadFactor / 3, fMaxLoadFactor] is fine,
|
||||||
|
// I think. After rehashing the load factor will be about
|
||||||
|
// fMaxLoadFactor * 2 / 3, respectively fMaxLoadFactor / 2.
|
||||||
|
float loadFactor = (float)fElementCount / (float)fArraySize;
|
||||||
|
if (loadFactor > fMaxLoadFactor
|
||||||
|
|| (fArraySize > fInitialSize && loadFactor < fMaxLoadFactor / 3)) {
|
||||||
|
return _Rehash();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// _Rehash
|
||||||
|
template<class Element, class ElementVec>
|
||||||
|
bool
|
||||||
|
OpenHashTable<Element, ElementVec>::_Rehash()
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
int32 newSize = int32(fElementCount * 1.73 * fMaxLoadFactor);
|
||||||
|
newSize = (fInitialSize > newSize ? fInitialSize : newSize);
|
||||||
|
if (newSize != fArraySize) {
|
||||||
|
// allocate a new array
|
||||||
|
int32 *newHashArray = (int32*)calloc(newSize, sizeof(int32));
|
||||||
|
if (newHashArray) {
|
||||||
|
// init the new hash array
|
||||||
|
for (int32 index = 0; index < newSize; index++)
|
||||||
|
newHashArray[index] = -1;
|
||||||
|
// iterate through all elements and put them into the new
|
||||||
|
// hash array
|
||||||
|
for (int i = 0; i < fArraySize; i++) {
|
||||||
|
int32 index = fHashArray[i];
|
||||||
|
while (index >= 0) {
|
||||||
|
// insert the element in the new array
|
||||||
|
Element &element = fElementVector->At(index);
|
||||||
|
int32 next = element.fNext;
|
||||||
|
uint32 hash = (element.Hash() % newSize);
|
||||||
|
element.fNext = newHashArray[hash];
|
||||||
|
newHashArray[hash] = index;
|
||||||
|
// next element in old list
|
||||||
|
index = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// delete the old array and set the new one
|
||||||
|
free(fHashArray);
|
||||||
|
fHashArray = newHashArray;
|
||||||
|
fArraySize = newSize;
|
||||||
|
} else
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
OpenHashElementArray<Element>::OpenHashElementArray(int32 initialSize)
|
||||||
|
: fSize(initialSize),
|
||||||
|
fNextFree(0),
|
||||||
|
fNextDeleted(-1)
|
||||||
|
{
|
||||||
|
fData = (Element*)calloc((size_t)initialSize, sizeof(Element));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
OpenHashElementArray<Element>::~OpenHashElementArray()
|
||||||
|
{
|
||||||
|
free(fData);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
bool
|
||||||
|
OpenHashElementArray<Element>::InitCheck() const
|
||||||
|
{
|
||||||
|
return fData;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
Element &
|
||||||
|
OpenHashElementArray<Element>::At(int32 index)
|
||||||
|
{
|
||||||
|
ASSERT(index < fSize);
|
||||||
|
return fData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
const Element &
|
||||||
|
OpenHashElementArray<Element>::At(int32 index) const
|
||||||
|
{
|
||||||
|
ASSERT(index < fSize);
|
||||||
|
return fData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
int32
|
||||||
|
OpenHashElementArray<Element>::IndexOf(const Element &element) const
|
||||||
|
{
|
||||||
|
int32 result = &element - fData;
|
||||||
|
if (result < 0 || result > fSize)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
int32
|
||||||
|
OpenHashElementArray<Element>::Size() const
|
||||||
|
{
|
||||||
|
return fSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
Element *
|
||||||
|
OpenHashElementArray<Element>::Add(const Element &newElement)
|
||||||
|
{
|
||||||
|
Element *element = Add();
|
||||||
|
if (element)
|
||||||
|
element.Adopt(newElement);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
const int32 kGrowChunk = 10;
|
||||||
|
#else
|
||||||
|
const int32 kGrowChunk = 1024;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
Element *
|
||||||
|
OpenHashElementArray<Element>::Add()
|
||||||
|
{
|
||||||
|
int32 index = fNextFree;
|
||||||
|
if (fNextDeleted >= 0) {
|
||||||
|
index = fNextDeleted;
|
||||||
|
fNextDeleted = At(index).fNext;
|
||||||
|
} else if (fNextFree >= fSize - 1) {
|
||||||
|
int32 newSize = fSize + kGrowChunk;
|
||||||
|
/*
|
||||||
|
Element *newData = (Element *)calloc((size_t)newSize , sizeof(Element));
|
||||||
|
if (!newData)
|
||||||
|
return NULL;
|
||||||
|
memcpy(newData, fData, fSize * sizeof(Element));
|
||||||
|
free(fData);
|
||||||
|
*/
|
||||||
|
Element *newData = (Element*)realloc(fData,
|
||||||
|
(size_t)newSize * sizeof(Element));
|
||||||
|
if (!newData)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fData = newData;
|
||||||
|
fSize = newSize;
|
||||||
|
index = fNextFree;
|
||||||
|
fNextFree++;
|
||||||
|
} else
|
||||||
|
fNextFree++;
|
||||||
|
|
||||||
|
new (&At(index)) Element;
|
||||||
|
// call placement new to initialize the element properly
|
||||||
|
ASSERT(At(index).fNext == -1);
|
||||||
|
|
||||||
|
return &At(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Element>
|
||||||
|
void
|
||||||
|
OpenHashElementArray<Element>::Remove(int32 index)
|
||||||
|
{
|
||||||
|
// delete by chaining empty elements in a single linked
|
||||||
|
// list, reusing the next field
|
||||||
|
ASSERT(index < fSize);
|
||||||
|
At(index).~Element();
|
||||||
|
// call the destructor explicitly to destroy the element
|
||||||
|
// properly
|
||||||
|
At(index).fNext = fNextDeleted;
|
||||||
|
fNextDeleted = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using BPrivate::OpenHashTable;
|
||||||
|
|
||||||
|
#endif // __OPEN_HASH_TABLE__
|
||||||
@@ -0,0 +1,514 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2010, Stephan Aßmus <[email protected]>.
|
||||||
|
* Copyright 1998, Eric Shepherd.
|
||||||
|
* All rights reserved. Distributed under the terms of the Be Sample Code
|
||||||
|
* license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! Be Newsletter Volume II, Issue 35; September 2, 1998 (Eric Shepherd)
|
||||||
|
|
||||||
|
#include "SettingsMessage.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <Autolock.h>
|
||||||
|
#include <Entry.h>
|
||||||
|
#include <File.h>
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
SettingsMessage::SettingsMessage(directory_which directory,
|
||||||
|
const char* filename)
|
||||||
|
:
|
||||||
|
BMessage('pref'),
|
||||||
|
fListeners(4)
|
||||||
|
{
|
||||||
|
fStatus = find_directory(directory, &fPath);
|
||||||
|
|
||||||
|
if (fStatus == B_OK)
|
||||||
|
fStatus = fPath.Append(filename);
|
||||||
|
|
||||||
|
if (fStatus == B_OK)
|
||||||
|
fStatus = Load();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsMessage::~SettingsMessage()
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
|
||||||
|
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
|
||||||
|
delete reinterpret_cast<BMessenger*>(fListeners.ItemAtFast(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::InitCheck() const
|
||||||
|
{
|
||||||
|
return fStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::Load()
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
BFile file(fPath.Path(), B_READ_ONLY);
|
||||||
|
status_t status = file.InitCheck();
|
||||||
|
|
||||||
|
if (status == B_OK)
|
||||||
|
status = Unflatten(&file);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::Save() const
|
||||||
|
{
|
||||||
|
BAutolock _(const_cast<SettingsMessage*>(this));
|
||||||
|
|
||||||
|
BFile file(fPath.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||||
|
status_t status = file.InitCheck();
|
||||||
|
|
||||||
|
if (status == B_OK)
|
||||||
|
status = Flatten(&file);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsMessage::AddListener(const BMessenger& listener)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
BMessenger* listenerCopy = new(std::nothrow) BMessenger(listener);
|
||||||
|
if (listenerCopy && fListeners.AddItem(listenerCopy))
|
||||||
|
return true;
|
||||||
|
delete listenerCopy;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsMessage::RemoveListener(const BMessenger& listener)
|
||||||
|
{
|
||||||
|
BAutolock _(this);
|
||||||
|
|
||||||
|
for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) {
|
||||||
|
BMessenger* listenerItem = reinterpret_cast<BMessenger*>(
|
||||||
|
fListeners.ItemAtFast(i));
|
||||||
|
if (*listenerItem == listener) {
|
||||||
|
fListeners.RemoveItem(i);
|
||||||
|
delete listenerItem;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, bool value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceBool(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddBool(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, int8 value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceInt8(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddInt8(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, int16 value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceInt16(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddInt16(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, int32 value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceInt32(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddInt32(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, uint32 value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceUInt32(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddUInt32(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, int64 value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceInt64(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddInt64(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, float value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceFloat(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddFloat(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, double value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceDouble(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddDouble(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const char* value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceString(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddString(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const BString& value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceString(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddString(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const BPoint& value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplacePoint(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddPoint(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const BRect& value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceRect(name, value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddRect(name, value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const entry_ref& value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceRef(name, &value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddRef(name, &value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const BMessage& value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceMessage(name, &value);
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddMessage(name, &value);
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const BFlattenable* value)
|
||||||
|
{
|
||||||
|
status_t ret = ReplaceFlat(name, const_cast<BFlattenable*>(value));
|
||||||
|
if (ret != B_OK)
|
||||||
|
ret = AddFlat(name, const_cast<BFlattenable*>(value));
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
SettingsMessage::SetValue(const char* name, const BFont& value)
|
||||||
|
{
|
||||||
|
font_family family;
|
||||||
|
font_style style;
|
||||||
|
value.GetFamilyAndStyle(&family, &style);
|
||||||
|
|
||||||
|
BMessage fontMessage;
|
||||||
|
status_t ret = fontMessage.AddString("family", family);
|
||||||
|
if (ret == B_OK)
|
||||||
|
ret = fontMessage.AddString("style", style);
|
||||||
|
if (ret == B_OK)
|
||||||
|
ret = fontMessage.AddFloat("size", value.Size());
|
||||||
|
|
||||||
|
if (ret == B_OK) {
|
||||||
|
if (ReplaceMessage(name, &fontMessage) != B_OK)
|
||||||
|
ret = AddMessage(name, &fontMessage);
|
||||||
|
}
|
||||||
|
if (ret == B_OK)
|
||||||
|
_NotifyValueChanged(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SettingsMessage::GetValue(const char* name, bool defaultValue) const
|
||||||
|
{
|
||||||
|
bool value;
|
||||||
|
if (FindBool(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int8
|
||||||
|
SettingsMessage::GetValue(const char* name, int8 defaultValue) const
|
||||||
|
{
|
||||||
|
int8 value;
|
||||||
|
if (FindInt8(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16
|
||||||
|
SettingsMessage::GetValue(const char* name, int16 defaultValue) const
|
||||||
|
{
|
||||||
|
int16 value;
|
||||||
|
if (FindInt16(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
SettingsMessage::GetValue(const char* name, int32 defaultValue) const
|
||||||
|
{
|
||||||
|
int32 value;
|
||||||
|
if (FindInt32(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
SettingsMessage::GetValue(const char* name, uint32 defaultValue) const
|
||||||
|
{
|
||||||
|
uint32 value;
|
||||||
|
if (FindUInt32(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int64
|
||||||
|
SettingsMessage::GetValue(const char* name, int64 defaultValue) const
|
||||||
|
{
|
||||||
|
int64 value;
|
||||||
|
if (FindInt64(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
SettingsMessage::GetValue(const char* name, float defaultValue) const
|
||||||
|
{
|
||||||
|
float value;
|
||||||
|
if (FindFloat(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
SettingsMessage::GetValue(const char* name, double defaultValue) const
|
||||||
|
{
|
||||||
|
double value;
|
||||||
|
if (FindDouble(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BString
|
||||||
|
SettingsMessage::GetValue(const char* name, const BString& defaultValue) const
|
||||||
|
{
|
||||||
|
BString value;
|
||||||
|
if (FindString(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
SettingsMessage::GetValue(const char* name, const char* defaultValue) const
|
||||||
|
{
|
||||||
|
const char* value;
|
||||||
|
if (FindString(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BPoint
|
||||||
|
SettingsMessage::GetValue(const char *name, BPoint defaultValue) const
|
||||||
|
{
|
||||||
|
BPoint value;
|
||||||
|
if (FindPoint(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
SettingsMessage::GetValue(const char* name, BRect defaultValue) const
|
||||||
|
{
|
||||||
|
BRect value;
|
||||||
|
if (FindRect(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
entry_ref
|
||||||
|
SettingsMessage::GetValue(const char* name, const entry_ref& defaultValue) const
|
||||||
|
{
|
||||||
|
entry_ref value;
|
||||||
|
if (FindRef(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BMessage
|
||||||
|
SettingsMessage::GetValue(const char* name, const BMessage& defaultValue) const
|
||||||
|
{
|
||||||
|
BMessage value;
|
||||||
|
if (FindMessage(name, &value) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BFont
|
||||||
|
SettingsMessage::GetValue(const char* name, const BFont& defaultValue) const
|
||||||
|
{
|
||||||
|
BMessage fontMessage;
|
||||||
|
if (FindMessage(name, &fontMessage) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
const char* family;
|
||||||
|
const char* style;
|
||||||
|
float size;
|
||||||
|
if (fontMessage.FindString("family", &family) != B_OK
|
||||||
|
|| fontMessage.FindString("style", &style) != B_OK
|
||||||
|
|| fontMessage.FindFloat("size", &size) != B_OK) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BFont value;
|
||||||
|
if (value.SetFamilyAndStyle(family, style) != B_OK)
|
||||||
|
return defaultValue;
|
||||||
|
|
||||||
|
value.SetSize(size);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - private
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SettingsMessage::_NotifyValueChanged(const char* name) const
|
||||||
|
{
|
||||||
|
BMessage message(SETTINGS_VALUE_CHANGED);
|
||||||
|
message.AddString("name", name);
|
||||||
|
|
||||||
|
// Add the value of that name to the notification.
|
||||||
|
type_code type;
|
||||||
|
if (GetInfo(name, &type) == B_OK) {
|
||||||
|
const void* data;
|
||||||
|
ssize_t numBytes;
|
||||||
|
if (FindData(name, type, &data, &numBytes) == B_OK)
|
||||||
|
message.AddData("value", type, data, numBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 count = fListeners.CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BMessenger* listener = reinterpret_cast<BMessenger*>(
|
||||||
|
fListeners.ItemAtFast(i));
|
||||||
|
listener->SendMessage(&message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2010 Stephan Aßmus <[email protected]>.
|
||||||
|
* Copyright 1998 Eric Shepherd.
|
||||||
|
* All rights reserved. Distributed under the terms of the Be Sample Code
|
||||||
|
* license.
|
||||||
|
*/
|
||||||
|
#ifndef SETTINGS_MESSAGE_H
|
||||||
|
#define SETTINGS_MESSAGE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <FindDirectory.h>
|
||||||
|
#include <Font.h>
|
||||||
|
#include <List.h>
|
||||||
|
#include <Locker.h>
|
||||||
|
#include <Message.h>
|
||||||
|
#include <Path.h>
|
||||||
|
|
||||||
|
class BMessenger;
|
||||||
|
class BString;
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SETTINGS_VALUE_CHANGED = '_svc'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsMessage : public BMessage, public BLocker {
|
||||||
|
public:
|
||||||
|
SettingsMessage(directory_which directory,
|
||||||
|
const char* filename);
|
||||||
|
virtual ~SettingsMessage();
|
||||||
|
|
||||||
|
|
||||||
|
status_t InitCheck() const;
|
||||||
|
status_t Load();
|
||||||
|
status_t Save() const;
|
||||||
|
|
||||||
|
bool AddListener(const BMessenger& listener);
|
||||||
|
void RemoveListener(const BMessenger& listener);
|
||||||
|
|
||||||
|
status_t SetValue(const char* name, bool value);
|
||||||
|
status_t SetValue(const char* name, int8 value);
|
||||||
|
status_t SetValue(const char* name, int16 value);
|
||||||
|
status_t SetValue(const char* name, int32 value);
|
||||||
|
status_t SetValue(const char* name, uint32 value);
|
||||||
|
status_t SetValue(const char* name, int64 value);
|
||||||
|
status_t SetValue(const char* name, float value);
|
||||||
|
status_t SetValue(const char* name, double value);
|
||||||
|
status_t SetValue(const char* name,
|
||||||
|
const char* value);
|
||||||
|
status_t SetValue(const char* name,
|
||||||
|
const BString& value);
|
||||||
|
status_t SetValue(const char *name,
|
||||||
|
const BPoint& value);
|
||||||
|
status_t SetValue(const char* name, const BRect& value);
|
||||||
|
status_t SetValue(const char* name,
|
||||||
|
const entry_ref& value);
|
||||||
|
status_t SetValue(const char* name,
|
||||||
|
const BMessage& value);
|
||||||
|
status_t SetValue(const char* name,
|
||||||
|
const BFlattenable* value);
|
||||||
|
status_t SetValue(const char* name,
|
||||||
|
const BFont& value);
|
||||||
|
|
||||||
|
bool GetValue(const char* name,
|
||||||
|
bool defaultValue) const;
|
||||||
|
int8 GetValue(const char* name,
|
||||||
|
int8 defaultValue) const;
|
||||||
|
int16 GetValue(const char* name,
|
||||||
|
int16 defaultValue) const;
|
||||||
|
int32 GetValue(const char* name,
|
||||||
|
int32 defaultValue) const;
|
||||||
|
uint32 GetValue(const char* name,
|
||||||
|
uint32 defaultValue) const;
|
||||||
|
int64 GetValue(const char* name,
|
||||||
|
int64 defaultValue) const;
|
||||||
|
float GetValue(const char* name,
|
||||||
|
float defaultValue) const;
|
||||||
|
double GetValue(const char* name,
|
||||||
|
double defaultValue) const;
|
||||||
|
const char* GetValue(const char* name,
|
||||||
|
const char* defaultValue) const;
|
||||||
|
BString GetValue(const char* name,
|
||||||
|
const BString& defaultValue) const;
|
||||||
|
BPoint GetValue(const char *name,
|
||||||
|
BPoint defaultValue) const;
|
||||||
|
BRect GetValue(const char* name,
|
||||||
|
BRect defaultValue) const;
|
||||||
|
entry_ref GetValue(const char* name,
|
||||||
|
const entry_ref& defaultValue) const;
|
||||||
|
BMessage GetValue(const char* name,
|
||||||
|
const BMessage& defaultValue) const;
|
||||||
|
BFont GetValue(const char* name,
|
||||||
|
const BFont& defaultValue) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _NotifyValueChanged(const char* name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BPath fPath;
|
||||||
|
status_t fStatus;
|
||||||
|
BList fListeners;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SETTINGS_MESSAGE_H
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Open Tracker License
|
||||||
|
|
||||||
|
Terms and Conditions
|
||||||
|
|
||||||
|
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice applies to all licensees
|
||||||
|
and shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||||
|
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||||
|
this Software without prior written authorization from Be Incorporated.
|
||||||
|
|
||||||
|
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||||
|
of Be Incorporated in the United States and other countries. Other brand product
|
||||||
|
names are registered trademarks or trademarks of their respective holders.
|
||||||
|
All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SLOW_MENU__
|
||||||
|
#define __SLOW_MENU__
|
||||||
|
|
||||||
|
#include <Menu.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <Debug.h>
|
||||||
|
|
||||||
|
// SlowMenu is a convenience class that makes it easier to
|
||||||
|
// use the AddDynamicItem callback to implement a menu that can
|
||||||
|
// checks periodically between creating new items and quits
|
||||||
|
// early if needed
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
class BSlowMenu : public BMenu {
|
||||||
|
public:
|
||||||
|
BSlowMenu(const char *title, menu_layout layout = B_ITEMS_IN_COLUMN);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool StartBuildingItemList();
|
||||||
|
// set up state to start building the item list
|
||||||
|
// returns false if setup failed
|
||||||
|
virtual bool AddNextItem() = 0;
|
||||||
|
// returns false if done
|
||||||
|
virtual void DoneBuildingItemList() = 0;
|
||||||
|
// default version adds items from itemList to menu and deletes
|
||||||
|
// the list; override to sort items first, etc.
|
||||||
|
|
||||||
|
virtual void ClearMenuBuildingState() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool AddDynamicItem(add_state state);
|
||||||
|
// this is the callback from BMenu, you shouldn't need to override this
|
||||||
|
|
||||||
|
bool fMenuBuilt;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
using namespace BPrivate;
|
||||||
|
|
||||||
|
#endif /* __SLOW_MENU__ */
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StringForSize.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
string_for_size(double size, char* string, size_t stringSize)
|
||||||
|
{
|
||||||
|
double kib = size / 1024.0;
|
||||||
|
if (kib < 1.0) {
|
||||||
|
snprintf(string, stringSize, "%d bytes", (int)size);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
double mib = kib / 1024.0;
|
||||||
|
if (mib < 1.0) {
|
||||||
|
snprintf(string, stringSize, "%3.2f KiB", kib);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
double gib = mib / 1024.0;
|
||||||
|
if (gib < 1.0) {
|
||||||
|
snprintf(string, stringSize, "%3.2f MiB", mib);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
double tib = gib / 1024.0;
|
||||||
|
if (tib < 1.0) {
|
||||||
|
snprintf(string, stringSize, "%3.2f GiB", gib);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
snprintf(string, stringSize, "%.2f TiB", tib);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010 Haiku Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef STRING_FOR_SIZE_H
|
||||||
|
#define STRING_FOR_SIZE_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
|
||||||
|
|
||||||
|
const char* string_for_size(double size, char* string, size_t stringSize);
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace BPrivate
|
||||||
|
|
||||||
|
|
||||||
|
using BPrivate::string_for_size;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // COLOR_QUANTIZER_H
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
const uint32 kWindowIconWidth = 13;
|
||||||
|
const uint32 kWindowIconHeight = 14;
|
||||||
|
const color_space kWindowIconFormat = B_RGBA32;
|
||||||
|
|
||||||
|
const unsigned char kWindowIconBits[] = {
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff,
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff,
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x78, 0x78, 0x78, 0xff, 0x66, 0xff, 0xff, 0xff, 0x66, 0xff, 0xff, 0xff,
|
||||||
|
0x66, 0xff, 0xff, 0xff, 0x66, 0xff, 0xff, 0xff, 0x66, 0xff, 0xff, 0xff, 0x66, 0xff, 0xff, 0xff,
|
||||||
|
0x66, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x78, 0x78, 0xff, 0x13, 0xaf, 0xff, 0xff,
|
||||||
|
0x13, 0xaf, 0xff, 0xff, 0x13, 0xaf, 0xff, 0xff, 0x13, 0xaf, 0xff, 0xff, 0x13, 0xaf, 0xff, 0xff,
|
||||||
|
0x13, 0xaf, 0xff, 0xff, 0x13, 0xaf, 0xff, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff,
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff, 0x78, 0x78, 0x78, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff, 0x78, 0x78, 0x78, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0x78, 0x78, 0x78, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2009, Ingo Weinhold <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "svn_revision.h"
|
||||||
|
|
||||||
|
const int32 kSVNRevision = 0;
|
||||||
|
// #include "svn_revision"
|
||||||
|
;
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2009, Ingo Weinhold <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SVN_REVISION_H
|
||||||
|
#define SVN_REVISION_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern const int32 kSVNRevision;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SVN_REVISION_H
|
||||||
@@ -0,0 +1,542 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Rene Gollent <[email protected]>
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TabContainerView.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <AbstractLayoutItem.h>
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <CardLayout.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <GroupView.h>
|
||||||
|
#include <MenuBar.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "TabView.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const float kLeftTabInset = 4;
|
||||||
|
|
||||||
|
|
||||||
|
TabContainerView::TabContainerView(Controller* controller)
|
||||||
|
:
|
||||||
|
BGroupView(B_HORIZONTAL, 0.0),
|
||||||
|
fLastMouseEventTab(NULL),
|
||||||
|
fMouseDown(false),
|
||||||
|
fClickCount(0),
|
||||||
|
fSelectedTab(NULL),
|
||||||
|
fController(controller),
|
||||||
|
fFirstVisibleTabIndex(0)
|
||||||
|
{
|
||||||
|
SetFlags(Flags() | B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
|
||||||
|
SetViewColor(B_TRANSPARENT_COLOR);
|
||||||
|
GroupLayout()->SetInsets(kLeftTabInset, 0, 0, 1);
|
||||||
|
GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue(), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabContainerView::~TabContainerView()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabContainerView::MinSize()
|
||||||
|
{
|
||||||
|
// Eventually, we want to be scrolling if the tabs don't fit.
|
||||||
|
BSize size(BGroupView::MinSize());
|
||||||
|
size.width = 300;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
default:
|
||||||
|
BGroupView::MessageReceived(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
// Stroke separator line at bottom.
|
||||||
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
BRect frame(Bounds());
|
||||||
|
SetHighColor(tint_color(base, B_DARKEN_2_TINT));
|
||||||
|
StrokeLine(frame.LeftBottom(), frame.RightBottom());
|
||||||
|
frame.bottom--;
|
||||||
|
|
||||||
|
// Draw empty area before first tab.
|
||||||
|
uint32 borders = BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER;
|
||||||
|
BRect leftFrame(frame.left, frame.top, kLeftTabInset, frame.bottom);
|
||||||
|
be_control_look->DrawInactiveTab(this, leftFrame, updateRect, base, 0,
|
||||||
|
borders);
|
||||||
|
|
||||||
|
// Draw all tabs, keeping track of where they end.
|
||||||
|
BGroupLayout* layout = GroupLayout();
|
||||||
|
int32 count = layout->CountItems() - 1;
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
layout->ItemAt(i));
|
||||||
|
if (!item || !item->IsVisible())
|
||||||
|
continue;
|
||||||
|
item->Parent()->Draw(updateRect);
|
||||||
|
frame.left = item->Frame().right + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw empty area after last tab.
|
||||||
|
be_control_look->DrawInactiveTab(this, frame, updateRect, base, 0, borders);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::MouseDown(BPoint where)
|
||||||
|
{
|
||||||
|
uint32 buttons;
|
||||||
|
if (Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons) != B_OK)
|
||||||
|
buttons = B_PRIMARY_MOUSE_BUTTON;
|
||||||
|
uint32 clicks;
|
||||||
|
if (Window()->CurrentMessage()->FindInt32("clicks", (int32*)&clicks) != B_OK)
|
||||||
|
clicks = 1;
|
||||||
|
fMouseDown = true;
|
||||||
|
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
|
||||||
|
if (fLastMouseEventTab)
|
||||||
|
fLastMouseEventTab->MouseDown(where, buttons);
|
||||||
|
else {
|
||||||
|
if ((buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
|
||||||
|
// Middle click outside tabs should always open a new tab.
|
||||||
|
fClickCount = 2;
|
||||||
|
} else if (clicks > 1)
|
||||||
|
fClickCount = fClickCount++;
|
||||||
|
else
|
||||||
|
fClickCount = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::MouseUp(BPoint where)
|
||||||
|
{
|
||||||
|
fMouseDown = false;
|
||||||
|
if (fLastMouseEventTab) {
|
||||||
|
fLastMouseEventTab->MouseUp(where);
|
||||||
|
fClickCount = 0;
|
||||||
|
} else if (fClickCount > 1) {
|
||||||
|
// NOTE: fClickCount is >= 1 only if the first click was outside
|
||||||
|
// any tab. So even if fLastMouseEventTab has been reset to NULL
|
||||||
|
// because this tab was removed during mouse down, we wouldn't
|
||||||
|
// run the "outside tabs" code below.
|
||||||
|
fController->DoubleClickOutsideTabs();
|
||||||
|
fClickCount = 0;
|
||||||
|
}
|
||||||
|
// Always check the tab under the mouse again, since we don't update
|
||||||
|
// it with fMouseDown == true.
|
||||||
|
_SendFakeMouseMoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage)
|
||||||
|
{
|
||||||
|
_MouseMoved(where, transit, dragMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::DoLayout()
|
||||||
|
{
|
||||||
|
BGroupView::DoLayout();
|
||||||
|
|
||||||
|
_ValidateTabVisibility();
|
||||||
|
_SendFakeMouseMoved();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::AddTab(const char* label, int32 index)
|
||||||
|
{
|
||||||
|
TabView* tab;
|
||||||
|
if (fController)
|
||||||
|
tab = fController->CreateTabView();
|
||||||
|
else
|
||||||
|
tab = new TabView();
|
||||||
|
tab->SetLabel(label);
|
||||||
|
AddTab(tab, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::AddTab(TabView* tab, int32 index)
|
||||||
|
{
|
||||||
|
tab->SetContainerView(this);
|
||||||
|
|
||||||
|
if (index == -1)
|
||||||
|
index = GroupLayout()->CountItems() - 1;
|
||||||
|
|
||||||
|
bool hasFrames = fController != NULL && fController->HasFrames();
|
||||||
|
bool isFirst = index == 0 && hasFrames;
|
||||||
|
bool isLast = index == GroupLayout()->CountItems() - 1 && hasFrames;
|
||||||
|
bool isFront = fSelectedTab == NULL;
|
||||||
|
tab->Update(isFirst, isLast, isFront);
|
||||||
|
|
||||||
|
GroupLayout()->AddItem(index, tab->LayoutItem());
|
||||||
|
|
||||||
|
if (isFront)
|
||||||
|
SelectTab(tab);
|
||||||
|
if (isLast) {
|
||||||
|
TabLayoutItem* item
|
||||||
|
= dynamic_cast<TabLayoutItem*>(GroupLayout()->ItemAt(index - 1));
|
||||||
|
if (item)
|
||||||
|
item->Parent()->SetIsLast(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetFirstVisibleTabIndex(MaxFirstVisibleTabIndex());
|
||||||
|
_ValidateTabVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
TabView*
|
||||||
|
TabContainerView::RemoveTab(int32 index)
|
||||||
|
{
|
||||||
|
TabLayoutItem* item
|
||||||
|
= dynamic_cast<TabLayoutItem*>(GroupLayout()->RemoveItem(index));
|
||||||
|
|
||||||
|
if (!item)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
BRect dirty(Bounds());
|
||||||
|
dirty.left = item->Frame().left;
|
||||||
|
TabView* removedTab = item->Parent();
|
||||||
|
removedTab->SetContainerView(NULL);
|
||||||
|
|
||||||
|
if (removedTab == fLastMouseEventTab)
|
||||||
|
fLastMouseEventTab = NULL;
|
||||||
|
|
||||||
|
// Update tabs after or before the removed tab.
|
||||||
|
bool hasFrames = fController != NULL && fController->HasFrames();
|
||||||
|
item = dynamic_cast<TabLayoutItem*>(GroupLayout()->ItemAt(index));
|
||||||
|
if (item) {
|
||||||
|
// This tab is behind the removed tab.
|
||||||
|
TabView* tab = item->Parent();
|
||||||
|
tab->Update(index == 0 && hasFrames,
|
||||||
|
index == GroupLayout()->CountItems() - 2 && hasFrames,
|
||||||
|
tab == fSelectedTab);
|
||||||
|
if (removedTab == fSelectedTab) {
|
||||||
|
fSelectedTab = NULL;
|
||||||
|
SelectTab(tab);
|
||||||
|
} else if (fController && tab == fSelectedTab)
|
||||||
|
fController->TabSelected(index);
|
||||||
|
} else {
|
||||||
|
// The removed tab was the last tab.
|
||||||
|
item = dynamic_cast<TabLayoutItem*>(GroupLayout()->ItemAt(index - 1));
|
||||||
|
if (item) {
|
||||||
|
TabView* tab = item->Parent();
|
||||||
|
tab->Update(index == 0 && hasFrames,
|
||||||
|
index == GroupLayout()->CountItems() - 2 && hasFrames,
|
||||||
|
tab == fSelectedTab);
|
||||||
|
if (removedTab == fSelectedTab) {
|
||||||
|
fSelectedTab = NULL;
|
||||||
|
SelectTab(tab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate(dirty);
|
||||||
|
_ValidateTabVisibility();
|
||||||
|
|
||||||
|
return removedTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabView*
|
||||||
|
TabContainerView::TabAt(int32 index) const
|
||||||
|
{
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
GroupLayout()->ItemAt(index));
|
||||||
|
if (item)
|
||||||
|
return item->Parent();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TabContainerView::IndexOf(TabView* tab) const
|
||||||
|
{
|
||||||
|
return GroupLayout()->IndexOfItem(tab->LayoutItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::SelectTab(int32 index)
|
||||||
|
{
|
||||||
|
TabView* tab = NULL;
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
GroupLayout()->ItemAt(index));
|
||||||
|
if (item)
|
||||||
|
tab = item->Parent();
|
||||||
|
|
||||||
|
SelectTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::SelectTab(TabView* tab)
|
||||||
|
{
|
||||||
|
if (tab == fSelectedTab)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fSelectedTab)
|
||||||
|
fSelectedTab->SetIsFront(false);
|
||||||
|
|
||||||
|
fSelectedTab = tab;
|
||||||
|
|
||||||
|
if (fSelectedTab)
|
||||||
|
fSelectedTab->SetIsFront(true);
|
||||||
|
|
||||||
|
if (fController != NULL) {
|
||||||
|
int32 index = -1;
|
||||||
|
if (fSelectedTab != NULL)
|
||||||
|
index = GroupLayout()->IndexOfItem(tab->LayoutItem());
|
||||||
|
|
||||||
|
if (!tab->LayoutItem()->IsVisible()) {
|
||||||
|
SetFirstVisibleTabIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
fController->TabSelected(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::SetTabLabel(int32 tabIndex, const char* label)
|
||||||
|
{
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
GroupLayout()->ItemAt(tabIndex));
|
||||||
|
if (item == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
item->Parent()->SetLabel(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::SetFirstVisibleTabIndex(int32 index)
|
||||||
|
{
|
||||||
|
if (index < 0)
|
||||||
|
index = 0;
|
||||||
|
if (index > MaxFirstVisibleTabIndex())
|
||||||
|
index = MaxFirstVisibleTabIndex();
|
||||||
|
if (fFirstVisibleTabIndex == index)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fFirstVisibleTabIndex = index;
|
||||||
|
|
||||||
|
_UpdateTabVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TabContainerView::FirstVisibleTabIndex() const
|
||||||
|
{
|
||||||
|
return fFirstVisibleTabIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TabContainerView::MaxFirstVisibleTabIndex() const
|
||||||
|
{
|
||||||
|
float availableWidth = _AvailableWidthForTabs();
|
||||||
|
if (availableWidth < 0)
|
||||||
|
return 0;
|
||||||
|
float visibleTabsWidth = 0;
|
||||||
|
|
||||||
|
BGroupLayout* layout = GroupLayout();
|
||||||
|
int32 i = layout->CountItems() - 2;
|
||||||
|
for (; i >= 0; i--) {
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
layout->ItemAt(i));
|
||||||
|
if (item == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float itemWidth = item->MinSize().width;
|
||||||
|
if (availableWidth >= visibleTabsWidth + itemWidth)
|
||||||
|
visibleTabsWidth += itemWidth;
|
||||||
|
else {
|
||||||
|
// The tab before this tab is the last one that can be visible.
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabContainerView::CanScrollLeft() const
|
||||||
|
{
|
||||||
|
return fFirstVisibleTabIndex < MaxFirstVisibleTabIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabContainerView::CanScrollRight() const
|
||||||
|
{
|
||||||
|
BGroupLayout* layout = GroupLayout();
|
||||||
|
int32 count = layout->CountItems() - 1;
|
||||||
|
if (count > 0) {
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
layout->ItemAt(count - 1));
|
||||||
|
return !item->IsVisible();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
TabView*
|
||||||
|
TabContainerView::_TabAt(const BPoint& where) const
|
||||||
|
{
|
||||||
|
BGroupLayout* layout = GroupLayout();
|
||||||
|
int32 count = layout->CountItems() - 1;
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(layout->ItemAt(i));
|
||||||
|
if (item == NULL || !item->IsVisible())
|
||||||
|
continue;
|
||||||
|
// Account for the fact that the tab frame does not contain the
|
||||||
|
// visible bottom border.
|
||||||
|
BRect frame = item->Frame();
|
||||||
|
frame.bottom++;
|
||||||
|
if (frame.Contains(where))
|
||||||
|
return item->Parent();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::_MouseMoved(BPoint where, uint32 _transit,
|
||||||
|
const BMessage* dragMessage)
|
||||||
|
{
|
||||||
|
TabView* tab = _TabAt(where);
|
||||||
|
if (fMouseDown) {
|
||||||
|
uint32 transit = tab == fLastMouseEventTab
|
||||||
|
? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||||
|
if (fLastMouseEventTab)
|
||||||
|
fLastMouseEventTab->MouseMoved(where, transit, dragMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fLastMouseEventTab != NULL && fLastMouseEventTab == tab)
|
||||||
|
fLastMouseEventTab->MouseMoved(where, B_INSIDE_VIEW, dragMessage);
|
||||||
|
else {
|
||||||
|
if (fLastMouseEventTab)
|
||||||
|
fLastMouseEventTab->MouseMoved(where, B_EXITED_VIEW, dragMessage);
|
||||||
|
fLastMouseEventTab = tab;
|
||||||
|
if (fLastMouseEventTab)
|
||||||
|
fLastMouseEventTab->MouseMoved(where, B_ENTERED_VIEW, dragMessage);
|
||||||
|
else
|
||||||
|
fController->SetToolTip("Double-click or middle-click to open new tab.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::_ValidateTabVisibility()
|
||||||
|
{
|
||||||
|
if (fFirstVisibleTabIndex > MaxFirstVisibleTabIndex())
|
||||||
|
SetFirstVisibleTabIndex(MaxFirstVisibleTabIndex());
|
||||||
|
else
|
||||||
|
_UpdateTabVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::_UpdateTabVisibility()
|
||||||
|
{
|
||||||
|
float availableWidth = _AvailableWidthForTabs();
|
||||||
|
if (availableWidth < 0)
|
||||||
|
return;
|
||||||
|
float visibleTabsWidth = 0;
|
||||||
|
|
||||||
|
bool canScrollTabsLeft = fFirstVisibleTabIndex > 0;
|
||||||
|
bool canScrollTabsRight = false;
|
||||||
|
|
||||||
|
BGroupLayout* layout = GroupLayout();
|
||||||
|
int32 count = layout->CountItems() - 1;
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
TabLayoutItem* item = dynamic_cast<TabLayoutItem*>(
|
||||||
|
layout->ItemAt(i));
|
||||||
|
if (i < fFirstVisibleTabIndex)
|
||||||
|
item->SetVisible(false);
|
||||||
|
else {
|
||||||
|
float itemWidth = item->MinSize().width;
|
||||||
|
bool visible = availableWidth >= visibleTabsWidth + itemWidth;
|
||||||
|
item->SetVisible(visible && !canScrollTabsRight);
|
||||||
|
visibleTabsWidth += itemWidth;
|
||||||
|
if (!visible)
|
||||||
|
canScrollTabsRight = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fController->UpdateTabScrollability(canScrollTabsLeft, canScrollTabsRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
TabContainerView::_AvailableWidthForTabs() const
|
||||||
|
{
|
||||||
|
float width = Bounds().Width() - 10;
|
||||||
|
// TODO: Don't really know why -10 is needed above.
|
||||||
|
|
||||||
|
float left;
|
||||||
|
float right;
|
||||||
|
GroupLayout()->GetInsets(&left, NULL, &right, NULL);
|
||||||
|
width -= left + right;
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabContainerView::_SendFakeMouseMoved()
|
||||||
|
{
|
||||||
|
BPoint where;
|
||||||
|
uint32 buttons;
|
||||||
|
GetMouse(&where, &buttons, false);
|
||||||
|
if (Bounds().Contains(where))
|
||||||
|
_MouseMoved(where, B_INSIDE_VIEW, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef TAB_CONTAINER_VIEW_H
|
||||||
|
#define TAB_CONTAINER_VIEW_H
|
||||||
|
|
||||||
|
#include <GroupView.h>
|
||||||
|
|
||||||
|
|
||||||
|
class TabView;
|
||||||
|
|
||||||
|
|
||||||
|
class TabContainerView : public BGroupView {
|
||||||
|
public:
|
||||||
|
class Controller {
|
||||||
|
public:
|
||||||
|
virtual void TabSelected(int32 tabIndex) = 0;
|
||||||
|
virtual bool HasFrames() = 0;
|
||||||
|
virtual TabView* CreateTabView() = 0;
|
||||||
|
virtual void DoubleClickOutsideTabs() = 0;
|
||||||
|
virtual void UpdateTabScrollability(bool canScrollLeft,
|
||||||
|
bool canScrollRight) = 0;
|
||||||
|
virtual void SetToolTip(const BString& text) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
TabContainerView(Controller* controller);
|
||||||
|
virtual ~TabContainerView();
|
||||||
|
|
||||||
|
virtual BSize MinSize();
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage*);
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect);
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where);
|
||||||
|
virtual void MouseUp(BPoint where);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
|
||||||
|
virtual void DoLayout();
|
||||||
|
|
||||||
|
void AddTab(const char* label, int32 index = -1);
|
||||||
|
void AddTab(TabView* tab, int32 index = -1);
|
||||||
|
TabView* RemoveTab(int32 index);
|
||||||
|
TabView* TabAt(int32 index) const;
|
||||||
|
|
||||||
|
int32 IndexOf(TabView* tab) const;
|
||||||
|
|
||||||
|
void SelectTab(int32 tabIndex);
|
||||||
|
void SelectTab(TabView* tab);
|
||||||
|
|
||||||
|
void SetTabLabel(int32 tabIndex, const char* label);
|
||||||
|
|
||||||
|
void SetFirstVisibleTabIndex(int32 index);
|
||||||
|
int32 FirstVisibleTabIndex() const;
|
||||||
|
int32 MaxFirstVisibleTabIndex() const;
|
||||||
|
|
||||||
|
bool CanScrollLeft() const;
|
||||||
|
bool CanScrollRight() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TabView* _TabAt(const BPoint& where) const;
|
||||||
|
void _MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
void _ValidateTabVisibility();
|
||||||
|
void _UpdateTabVisibility();
|
||||||
|
float _AvailableWidthForTabs() const;
|
||||||
|
void _SendFakeMouseMoved();
|
||||||
|
|
||||||
|
private:
|
||||||
|
TabView* fLastMouseEventTab;
|
||||||
|
bool fMouseDown;
|
||||||
|
uint32 fClickCount;
|
||||||
|
TabView* fSelectedTab;
|
||||||
|
Controller* fController;
|
||||||
|
int32 fFirstVisibleTabIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TAB_CONTAINER_VIEW_H
|
||||||
@@ -0,0 +1,940 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Rene Gollent <[email protected]>
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TabManager.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <AbstractLayoutItem.h>
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <CardLayout.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <GroupView.h>
|
||||||
|
#include <MenuBar.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <Rect.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "TabContainerView.h"
|
||||||
|
#include "TabView.h"
|
||||||
|
|
||||||
|
|
||||||
|
const static BString kEmptyString;
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Helper classes
|
||||||
|
|
||||||
|
|
||||||
|
class TabButton : public BButton {
|
||||||
|
public:
|
||||||
|
TabButton(BMessage* message)
|
||||||
|
: BButton("", message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(12, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect bounds(Bounds());
|
||||||
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
SetHighColor(tint_color(base, B_DARKEN_2_TINT));
|
||||||
|
StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
|
||||||
|
bounds.bottom--;
|
||||||
|
uint32 flags = be_control_look->Flags(this);
|
||||||
|
uint32 borders = BControlLook::B_TOP_BORDER
|
||||||
|
| BControlLook::B_BOTTOM_BORDER;
|
||||||
|
be_control_look->DrawInactiveTab(this, bounds, updateRect, base,
|
||||||
|
0, borders);
|
||||||
|
if (IsEnabled()) {
|
||||||
|
rgb_color button = tint_color(base, 1.07);
|
||||||
|
be_control_look->DrawButtonBackground(this, bounds, updateRect,
|
||||||
|
button, flags, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bounds.left = (bounds.left + bounds.right) / 2 - 6;
|
||||||
|
bounds.top = (bounds.top + bounds.bottom) / 2 - 6;
|
||||||
|
bounds.right = bounds.left + 12;
|
||||||
|
bounds.bottom = bounds.top + 12;
|
||||||
|
DrawSymbol(bounds, updateRect, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DrawSymbol(BRect frame, const BRect& updateRect,
|
||||||
|
const rgb_color& base)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollLeftTabButton : public TabButton {
|
||||||
|
public:
|
||||||
|
ScrollLeftTabButton(BMessage* message)
|
||||||
|
: TabButton(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DrawSymbol(BRect frame, const BRect& updateRect,
|
||||||
|
const rgb_color& base)
|
||||||
|
{
|
||||||
|
float tint = IsEnabled() ? B_DARKEN_4_TINT : B_DARKEN_1_TINT;
|
||||||
|
be_control_look->DrawArrowShape(this, frame, updateRect,
|
||||||
|
base, BControlLook::B_LEFT_ARROW, 0, tint);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ScrollRightTabButton : public TabButton {
|
||||||
|
public:
|
||||||
|
ScrollRightTabButton(BMessage* message)
|
||||||
|
: TabButton(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DrawSymbol(BRect frame, const BRect& updateRect,
|
||||||
|
const rgb_color& base)
|
||||||
|
{
|
||||||
|
frame.OffsetBy(1, 0);
|
||||||
|
float tint = IsEnabled() ? B_DARKEN_4_TINT : B_DARKEN_1_TINT;
|
||||||
|
be_control_look->DrawArrowShape(this, frame, updateRect,
|
||||||
|
base, BControlLook::B_RIGHT_ARROW, 0, tint);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class NewTabButton : public TabButton {
|
||||||
|
public:
|
||||||
|
NewTabButton(BMessage* message)
|
||||||
|
: TabButton(message)
|
||||||
|
{
|
||||||
|
SetToolTip("New tab (Cmd-T)");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(18, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DrawSymbol(BRect frame, const BRect& updateRect,
|
||||||
|
const rgb_color& base)
|
||||||
|
{
|
||||||
|
SetHighColor(tint_color(base, B_DARKEN_4_TINT));
|
||||||
|
float inset = 3;
|
||||||
|
frame.InsetBy(2, 2);
|
||||||
|
frame.top++;
|
||||||
|
frame.left++;
|
||||||
|
FillRoundRect(BRect(frame.left, frame.top + inset,
|
||||||
|
frame.right, frame.bottom - inset), 1, 1);
|
||||||
|
FillRoundRect(BRect(frame.left + inset, frame.top,
|
||||||
|
frame.right - inset, frame.bottom), 1, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TabMenuTabButton : public TabButton {
|
||||||
|
public:
|
||||||
|
TabMenuTabButton(BMessage* message)
|
||||||
|
: TabButton(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(18, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DrawSymbol(BRect frame, const BRect& updateRect,
|
||||||
|
const rgb_color& base)
|
||||||
|
{
|
||||||
|
be_control_look->DrawArrowShape(this, frame, updateRect,
|
||||||
|
base, BControlLook::B_DOWN_ARROW, 0, B_DARKEN_4_TINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint point)
|
||||||
|
{
|
||||||
|
if (!IsEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Invoke must be called before setting B_CONTROL_ON
|
||||||
|
// for the button to stay "down"
|
||||||
|
Invoke();
|
||||||
|
SetValue(B_CONTROL_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MouseUp(BPoint point)
|
||||||
|
{
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuClosed()
|
||||||
|
{
|
||||||
|
SetValue(B_CONTROL_OFF);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_SCROLL_TABS_LEFT = 'stlt',
|
||||||
|
MSG_SCROLL_TABS_RIGHT = 'strt',
|
||||||
|
MSG_OPEN_TAB_MENU = 'otmn'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TabContainerGroup : public BGroupView {
|
||||||
|
public:
|
||||||
|
TabContainerGroup(TabContainerView* tabContainerView)
|
||||||
|
:
|
||||||
|
BGroupView(B_HORIZONTAL, 0.0),
|
||||||
|
fTabContainerView(tabContainerView),
|
||||||
|
fScrollLeftTabButton(NULL),
|
||||||
|
fScrollRightTabButton(NULL),
|
||||||
|
fTabMenuButton(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void AttachedToWindow()
|
||||||
|
{
|
||||||
|
if (fScrollLeftTabButton != NULL)
|
||||||
|
fScrollLeftTabButton->SetTarget(this);
|
||||||
|
if (fScrollRightTabButton != NULL)
|
||||||
|
fScrollRightTabButton->SetTarget(this);
|
||||||
|
if (fTabMenuButton != NULL)
|
||||||
|
fTabMenuButton->SetTarget(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
switch (message->what) {
|
||||||
|
case MSG_SCROLL_TABS_LEFT:
|
||||||
|
fTabContainerView->SetFirstVisibleTabIndex(
|
||||||
|
fTabContainerView->FirstVisibleTabIndex() - 1);
|
||||||
|
break;
|
||||||
|
case MSG_SCROLL_TABS_RIGHT:
|
||||||
|
fTabContainerView->SetFirstVisibleTabIndex(
|
||||||
|
fTabContainerView->FirstVisibleTabIndex() + 1);
|
||||||
|
break;
|
||||||
|
case MSG_OPEN_TAB_MENU:
|
||||||
|
{
|
||||||
|
BPopUpMenu* tabMenu = new BPopUpMenu("tab menu", true, false);
|
||||||
|
int tabCount = fTabContainerView->GetLayout()->CountItems();
|
||||||
|
for (int i = 0; i < tabCount; i++) {
|
||||||
|
TabView* tab = fTabContainerView->TabAt(i);
|
||||||
|
if (tab) {
|
||||||
|
BMenuItem* item = new BMenuItem(tab->Label(), NULL);
|
||||||
|
tabMenu->AddItem(item);
|
||||||
|
if (tab->IsFront())
|
||||||
|
item->SetMarked(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force layout to get the final menu size. InvalidateLayout()
|
||||||
|
// did not seem to work here.
|
||||||
|
tabMenu->AttachedToWindow();
|
||||||
|
BRect buttonFrame = fTabMenuButton->Frame();
|
||||||
|
BRect menuFrame = tabMenu->Frame();
|
||||||
|
BPoint openPoint = ConvertToScreen(buttonFrame.LeftBottom());
|
||||||
|
// Open with the right side of the menu aligned with the right
|
||||||
|
// side of the button and a little below.
|
||||||
|
openPoint.x -= menuFrame.Width() - buttonFrame.Width();
|
||||||
|
openPoint.y += 2;
|
||||||
|
|
||||||
|
BMenuItem *selected = tabMenu->Go(openPoint, false, false,
|
||||||
|
ConvertToScreen(buttonFrame));
|
||||||
|
if (selected) {
|
||||||
|
selected->SetMarked(true);
|
||||||
|
int32 index = tabMenu->IndexOf(selected);
|
||||||
|
if (index != B_ERROR)
|
||||||
|
fTabContainerView->SelectTab(index);
|
||||||
|
}
|
||||||
|
fTabMenuButton->MenuClosed();
|
||||||
|
delete tabMenu;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
BGroupView::MessageReceived(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddScrollLeftButton(TabButton* button)
|
||||||
|
{
|
||||||
|
fScrollLeftTabButton = button;
|
||||||
|
GroupLayout()->AddView(button, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddScrollRightButton(TabButton* button)
|
||||||
|
{
|
||||||
|
fScrollRightTabButton = button;
|
||||||
|
GroupLayout()->AddView(button, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTabMenuButton(TabMenuTabButton* button)
|
||||||
|
{
|
||||||
|
fTabMenuButton = button;
|
||||||
|
GroupLayout()->AddView(button, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnableScrollButtons(bool canScrollLeft, bool canScrollRight)
|
||||||
|
{
|
||||||
|
fScrollLeftTabButton->SetEnabled(canScrollLeft);
|
||||||
|
fScrollRightTabButton->SetEnabled(canScrollRight);
|
||||||
|
if (!canScrollLeft && !canScrollRight) {
|
||||||
|
// hide scroll buttons
|
||||||
|
} else {
|
||||||
|
// show scroll buttons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TabContainerView* fTabContainerView;
|
||||||
|
TabButton* fScrollLeftTabButton;
|
||||||
|
TabButton* fScrollRightTabButton;
|
||||||
|
TabMenuTabButton* fTabMenuButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TabButtonContainer : public BGroupView {
|
||||||
|
public:
|
||||||
|
TabButtonContainer()
|
||||||
|
:
|
||||||
|
BGroupView(B_HORIZONTAL, 0.0)
|
||||||
|
{
|
||||||
|
SetFlags(Flags() | B_WILL_DRAW);
|
||||||
|
SetViewColor(B_TRANSPARENT_COLOR);
|
||||||
|
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
GroupLayout()->SetInsets(0, 6, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect bounds(Bounds());
|
||||||
|
rgb_color base = LowColor();
|
||||||
|
be_control_look->DrawInactiveTab(this, bounds, updateRect,
|
||||||
|
base, 0, BControlLook::B_TOP_BORDER);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TabManagerController : public TabContainerView::Controller {
|
||||||
|
public:
|
||||||
|
TabManagerController(TabManager* manager);
|
||||||
|
|
||||||
|
virtual ~TabManagerController();
|
||||||
|
|
||||||
|
virtual void TabSelected(int32 index)
|
||||||
|
{
|
||||||
|
fManager->SelectTab(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool HasFrames()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual TabView* CreateTabView();
|
||||||
|
|
||||||
|
virtual void DoubleClickOutsideTabs();
|
||||||
|
|
||||||
|
virtual void UpdateTabScrollability(bool canScrollLeft,
|
||||||
|
bool canScrollRight)
|
||||||
|
{
|
||||||
|
fTabContainerGroup->EnableScrollButtons(canScrollLeft, canScrollRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetToolTip(const BString& text)
|
||||||
|
{
|
||||||
|
if (fCurrentToolTip == text)
|
||||||
|
return;
|
||||||
|
fCurrentToolTip = text;
|
||||||
|
fManager->GetTabContainerView()->HideToolTip();
|
||||||
|
fManager->GetTabContainerView()->SetToolTip(
|
||||||
|
reinterpret_cast<BToolTip*>(NULL));
|
||||||
|
fManager->GetTabContainerView()->SetToolTip(fCurrentToolTip.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseTab(int32 index);
|
||||||
|
|
||||||
|
void SetCloseButtonsAvailable(bool available)
|
||||||
|
{
|
||||||
|
fCloseButtonsAvailable = available;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CloseButtonsAvailable() const
|
||||||
|
{
|
||||||
|
return fCloseButtonsAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDoubleClickOutsideTabsMessage(const BMessage& message,
|
||||||
|
const BMessenger& target);
|
||||||
|
|
||||||
|
void SetTabContainerGroup(TabContainerGroup* tabContainerGroup)
|
||||||
|
{
|
||||||
|
fTabContainerGroup = tabContainerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TabManager* fManager;
|
||||||
|
TabContainerGroup* fTabContainerGroup;
|
||||||
|
bool fCloseButtonsAvailable;
|
||||||
|
BMessage* fDoubleClickOutsideTabsMessage;
|
||||||
|
BMessenger fTarget;
|
||||||
|
BString fCurrentToolTip;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - WebTabView
|
||||||
|
|
||||||
|
|
||||||
|
class WebTabView : public TabView {
|
||||||
|
public:
|
||||||
|
WebTabView(TabManagerController* controller);
|
||||||
|
~WebTabView();
|
||||||
|
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
|
||||||
|
virtual void DrawContents(BView* owner, BRect frame, const BRect& updateRect,
|
||||||
|
bool isFirst, bool isLast, bool isFront);
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, uint32 buttons);
|
||||||
|
virtual void MouseUp(BPoint where);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
|
||||||
|
void SetIcon(const BBitmap* icon);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _DrawCloseButton(BView* owner, BRect& frame, const BRect& updateRect,
|
||||||
|
bool isFirst, bool isLast, bool isFront);
|
||||||
|
BRect _CloseRectFrame(BRect frame) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BBitmap* fIcon;
|
||||||
|
TabManagerController* fController;
|
||||||
|
bool fOverCloseRect;
|
||||||
|
bool fClicked;
|
||||||
|
bool fCloseOnMouseUp;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WebTabView::WebTabView(TabManagerController* controller)
|
||||||
|
:
|
||||||
|
TabView(),
|
||||||
|
fIcon(NULL),
|
||||||
|
fController(controller),
|
||||||
|
fOverCloseRect(false),
|
||||||
|
fClicked(false),
|
||||||
|
fCloseOnMouseUp(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WebTabView::~WebTabView()
|
||||||
|
{
|
||||||
|
delete fIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const int kIconSize = 18;
|
||||||
|
static const int kIconInset = 3;
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
WebTabView::MaxSize()
|
||||||
|
{
|
||||||
|
// Account for icon.
|
||||||
|
BSize size(TabView::MaxSize());
|
||||||
|
size.height = max_c(size.height, kIconSize + kIconInset * 2);
|
||||||
|
if (fIcon)
|
||||||
|
size.width += kIconSize + kIconInset * 2;
|
||||||
|
// Account for close button.
|
||||||
|
size.width += size.height;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebTabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect,
|
||||||
|
bool isFirst, bool isLast, bool isFront)
|
||||||
|
{
|
||||||
|
if (fController->CloseButtonsAvailable())
|
||||||
|
_DrawCloseButton(owner, frame, updateRect, isFirst, isLast, isFront);
|
||||||
|
|
||||||
|
if (fIcon) {
|
||||||
|
BRect iconBounds(0, 0, kIconSize - 1, kIconSize - 1);
|
||||||
|
// clip to icon bounds, if they are smaller
|
||||||
|
if (iconBounds.Contains(fIcon->Bounds()))
|
||||||
|
iconBounds = fIcon->Bounds();
|
||||||
|
else {
|
||||||
|
// Try to scale down the icon by an even factor so the
|
||||||
|
// final size is between 14 and 18 pixel size. If this fails,
|
||||||
|
// the icon will simply be displayed at 18x18.
|
||||||
|
float scale = 2;
|
||||||
|
while ((fIcon->Bounds().Width() + 1) / scale > kIconSize)
|
||||||
|
scale *= 2;
|
||||||
|
if ((fIcon->Bounds().Width() + 1) / scale >= kIconSize - 4
|
||||||
|
&& (fIcon->Bounds().Height() + 1) / scale >= kIconSize - 4
|
||||||
|
&& (fIcon->Bounds().Height() + 1) / scale <= kIconSize) {
|
||||||
|
iconBounds.right = (fIcon->Bounds().Width() + 1) / scale - 1;
|
||||||
|
iconBounds.bottom = (fIcon->Bounds().Height() + 1) / scale - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BPoint iconPos(frame.left + kIconInset - 1,
|
||||||
|
frame.top + floorf((frame.Height() - iconBounds.Height()) / 2));
|
||||||
|
iconBounds.OffsetTo(iconPos);
|
||||||
|
owner->SetDrawingMode(B_OP_ALPHA);
|
||||||
|
owner->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||||
|
owner->DrawBitmap(fIcon, fIcon->Bounds(), iconBounds,
|
||||||
|
B_FILTER_BITMAP_BILINEAR);
|
||||||
|
owner->SetDrawingMode(B_OP_COPY);
|
||||||
|
frame.left = frame.left + kIconSize + kIconInset * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
TabView::DrawContents(owner, frame, updateRect, isFirst, isLast, isFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebTabView::MouseDown(BPoint where, uint32 buttons)
|
||||||
|
{
|
||||||
|
if (buttons & B_TERTIARY_MOUSE_BUTTON) {
|
||||||
|
fCloseOnMouseUp = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect closeRect = _CloseRectFrame(Frame());
|
||||||
|
if (!fController->CloseButtonsAvailable() || !closeRect.Contains(where)) {
|
||||||
|
TabView::MouseDown(where, buttons);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fClicked = true;
|
||||||
|
ContainerView()->Invalidate(closeRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebTabView::MouseUp(BPoint where)
|
||||||
|
{
|
||||||
|
if (!fClicked && !fCloseOnMouseUp) {
|
||||||
|
TabView::MouseUp(where);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fCloseOnMouseUp && Frame().Contains(where)) {
|
||||||
|
fCloseOnMouseUp = false;
|
||||||
|
fController->CloseTab(ContainerView()->IndexOf(this));
|
||||||
|
// Probably this object is toast now, better return here.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fClicked = false;
|
||||||
|
fCloseOnMouseUp = false;
|
||||||
|
|
||||||
|
if (_CloseRectFrame(Frame()).Contains(where))
|
||||||
|
fController->CloseTab(ContainerView()->IndexOf(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebTabView::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage)
|
||||||
|
{
|
||||||
|
if (fController->CloseButtonsAvailable()) {
|
||||||
|
BRect closeRect = _CloseRectFrame(Frame());
|
||||||
|
bool overCloseRect = closeRect.Contains(where);
|
||||||
|
if (overCloseRect != fOverCloseRect) {
|
||||||
|
fOverCloseRect = overCloseRect;
|
||||||
|
ContainerView()->Invalidate(closeRect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fController->SetToolTip(Label());
|
||||||
|
|
||||||
|
TabView::MouseMoved(where, transit, dragMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WebTabView::SetIcon(const BBitmap* icon)
|
||||||
|
{
|
||||||
|
delete fIcon;
|
||||||
|
if (icon)
|
||||||
|
fIcon = new BBitmap(icon);
|
||||||
|
else
|
||||||
|
fIcon = NULL;
|
||||||
|
LayoutItem()->InvalidateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
WebTabView::_CloseRectFrame(BRect frame) const
|
||||||
|
{
|
||||||
|
frame.left = frame.right - frame.Height();
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void WebTabView::_DrawCloseButton(BView* owner, BRect& frame,
|
||||||
|
const BRect& updateRect, bool isFirst, bool isLast, bool isFront)
|
||||||
|
{
|
||||||
|
BRect closeRect = _CloseRectFrame(frame);
|
||||||
|
frame.right = closeRect.left - be_control_look->DefaultLabelSpacing();
|
||||||
|
|
||||||
|
closeRect.left = (closeRect.left + closeRect.right) / 2 - 3;
|
||||||
|
closeRect.right = closeRect.left + 6;
|
||||||
|
closeRect.top = (closeRect.top + closeRect.bottom) / 2 - 3;
|
||||||
|
closeRect.bottom = closeRect.top + 6;
|
||||||
|
|
||||||
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
float tint = B_DARKEN_1_TINT;
|
||||||
|
if (!IsFront()) {
|
||||||
|
base = tint_color(base, tint);
|
||||||
|
tint *= 1.02;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fOverCloseRect)
|
||||||
|
tint *= 1.2;
|
||||||
|
|
||||||
|
if (fClicked && fOverCloseRect) {
|
||||||
|
BRect buttonRect(closeRect.InsetByCopy(-4, -4));
|
||||||
|
be_control_look->DrawButtonFrame(owner, buttonRect, updateRect,
|
||||||
|
base, base,
|
||||||
|
BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME);
|
||||||
|
be_control_look->DrawButtonBackground(owner, buttonRect, updateRect,
|
||||||
|
base, BControlLook::B_ACTIVATED);
|
||||||
|
tint *= 1.2;
|
||||||
|
closeRect.OffsetBy(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
base = tint_color(base, tint);
|
||||||
|
owner->SetHighColor(base);
|
||||||
|
owner->SetPenSize(2);
|
||||||
|
owner->StrokeLine(closeRect.LeftTop(), closeRect.RightBottom());
|
||||||
|
owner->StrokeLine(closeRect.LeftBottom(), closeRect.RightTop());
|
||||||
|
owner->SetPenSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TabManagerController
|
||||||
|
|
||||||
|
|
||||||
|
TabManagerController::TabManagerController(TabManager* manager)
|
||||||
|
:
|
||||||
|
fManager(manager),
|
||||||
|
fTabContainerGroup(NULL),
|
||||||
|
fCloseButtonsAvailable(false),
|
||||||
|
fDoubleClickOutsideTabsMessage(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabManagerController::~TabManagerController()
|
||||||
|
{
|
||||||
|
delete fDoubleClickOutsideTabsMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabView*
|
||||||
|
TabManagerController::CreateTabView()
|
||||||
|
{
|
||||||
|
return new WebTabView(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManagerController::DoubleClickOutsideTabs()
|
||||||
|
{
|
||||||
|
fTarget.SendMessage(fDoubleClickOutsideTabsMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManagerController::CloseTab(int32 index)
|
||||||
|
{
|
||||||
|
fManager->CloseTab(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManagerController::SetDoubleClickOutsideTabsMessage(const BMessage& message,
|
||||||
|
const BMessenger& target)
|
||||||
|
{
|
||||||
|
delete fDoubleClickOutsideTabsMessage;
|
||||||
|
fDoubleClickOutsideTabsMessage = new BMessage(message);
|
||||||
|
fTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TabManager
|
||||||
|
|
||||||
|
|
||||||
|
TabManager::TabManager(const BMessenger& target, BMessage* newTabMessage)
|
||||||
|
:
|
||||||
|
fController(new TabManagerController(this)),
|
||||||
|
fTarget(target)
|
||||||
|
{
|
||||||
|
fController->SetDoubleClickOutsideTabsMessage(*newTabMessage,
|
||||||
|
be_app_messenger);
|
||||||
|
|
||||||
|
fContainerView = new BView("web view container", 0);
|
||||||
|
fCardLayout = new BCardLayout();
|
||||||
|
fContainerView->SetLayout(fCardLayout);
|
||||||
|
|
||||||
|
fTabContainerView = new TabContainerView(fController);
|
||||||
|
fTabContainerGroup = new TabContainerGroup(fTabContainerView);
|
||||||
|
fTabContainerGroup->GroupLayout()->SetInsets(0, 3, 0, 0);
|
||||||
|
|
||||||
|
fController->SetTabContainerGroup(fTabContainerGroup);
|
||||||
|
|
||||||
|
#if INTEGRATE_MENU_INTO_TAB_BAR
|
||||||
|
fMenu = new BMenu("Menu");
|
||||||
|
BMenuBar* menuBar = new BMenuBar("Menu bar");
|
||||||
|
menuBar->AddItem(fMenu);
|
||||||
|
TabButtonContainer* menuBarContainer = new TabButtonContainer();
|
||||||
|
menuBarContainer->GroupLayout()->AddView(menuBar);
|
||||||
|
fTabContainerGroup->GroupLayout()->AddView(menuBarContainer, 0.0f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fTabContainerGroup->GroupLayout()->AddView(fTabContainerView);
|
||||||
|
fTabContainerGroup->AddScrollLeftButton(new ScrollLeftTabButton(
|
||||||
|
new BMessage(MSG_SCROLL_TABS_LEFT)));
|
||||||
|
fTabContainerGroup->AddScrollRightButton(new ScrollRightTabButton(
|
||||||
|
new BMessage(MSG_SCROLL_TABS_RIGHT)));
|
||||||
|
NewTabButton* newTabButton = new NewTabButton(newTabMessage);
|
||||||
|
newTabButton->SetTarget(be_app);
|
||||||
|
fTabContainerGroup->GroupLayout()->AddView(newTabButton, 0.0f);
|
||||||
|
fTabContainerGroup->AddTabMenuButton(new TabMenuTabButton(
|
||||||
|
new BMessage(MSG_OPEN_TAB_MENU)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabManager::~TabManager()
|
||||||
|
{
|
||||||
|
delete fController;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::SetTarget(const BMessenger& target)
|
||||||
|
{
|
||||||
|
fTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BMessenger&
|
||||||
|
TabManager::Target() const
|
||||||
|
{
|
||||||
|
return fTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if INTEGRATE_MENU_INTO_TAB_BAR
|
||||||
|
BMenu*
|
||||||
|
TabManager::Menu() const
|
||||||
|
{
|
||||||
|
return fMenu;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
TabManager::TabGroup() const
|
||||||
|
{
|
||||||
|
return fTabContainerGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
TabManager::GetTabContainerView() const
|
||||||
|
{
|
||||||
|
return fTabContainerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
TabManager::ContainerView() const
|
||||||
|
{
|
||||||
|
return fContainerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
TabManager::ViewForTab(int32 tabIndex) const
|
||||||
|
{
|
||||||
|
BLayoutItem* item = fCardLayout->ItemAt(tabIndex);
|
||||||
|
if (item != NULL)
|
||||||
|
return item->View();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TabManager::TabForView(const BView* containedView) const
|
||||||
|
{
|
||||||
|
int32 count = fCardLayout->CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++) {
|
||||||
|
BLayoutItem* item = fCardLayout->ItemAt(i);
|
||||||
|
if (item->View() == containedView)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabManager::HasView(const BView* containedView) const
|
||||||
|
{
|
||||||
|
return TabForView(containedView) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::SelectTab(int32 tabIndex)
|
||||||
|
{
|
||||||
|
fCardLayout->SetVisibleItem(tabIndex);
|
||||||
|
fTabContainerView->SelectTab(tabIndex);
|
||||||
|
|
||||||
|
BMessage message(TAB_CHANGED);
|
||||||
|
message.AddInt32("tab index", tabIndex);
|
||||||
|
fTarget.SendMessage(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::SelectTab(const BView* containedView)
|
||||||
|
{
|
||||||
|
int32 tabIndex = TabForView(containedView);
|
||||||
|
if (tabIndex > 0)
|
||||||
|
SelectTab(tabIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TabManager::SelectedTabIndex() const
|
||||||
|
{
|
||||||
|
return fCardLayout->VisibleIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::CloseTab(int32 tabIndex)
|
||||||
|
{
|
||||||
|
BMessage message(CLOSE_TAB);
|
||||||
|
message.AddInt32("tab index", tabIndex);
|
||||||
|
fTarget.SendMessage(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::AddTab(BView* view, const char* label, int32 index)
|
||||||
|
{
|
||||||
|
fTabContainerView->AddTab(label, index);
|
||||||
|
fCardLayout->AddView(index, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
TabManager::RemoveTab(int32 index)
|
||||||
|
{
|
||||||
|
// It's important to remove the view first, since
|
||||||
|
// removing the tab will preliminary mess with the selected tab
|
||||||
|
// and then item count of card layout and tab container will not
|
||||||
|
// match yet.
|
||||||
|
BLayoutItem* item = fCardLayout->RemoveItem(index);
|
||||||
|
if (item == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
TabView* tab = fTabContainerView->RemoveTab(index);
|
||||||
|
delete tab;
|
||||||
|
|
||||||
|
BView* view = item->View();
|
||||||
|
delete item;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
TabManager::CountTabs() const
|
||||||
|
{
|
||||||
|
return fCardLayout->CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::SetTabLabel(int32 tabIndex, const char* label)
|
||||||
|
{
|
||||||
|
fTabContainerView->SetTabLabel(tabIndex, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BString&
|
||||||
|
TabManager::TabLabel(int32 tabIndex)
|
||||||
|
{
|
||||||
|
TabView* tab = fTabContainerView->TabAt(tabIndex);
|
||||||
|
if (tab)
|
||||||
|
return tab->Label();
|
||||||
|
else
|
||||||
|
return kEmptyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::SetTabIcon(const BView* containedView, const BBitmap* icon)
|
||||||
|
{
|
||||||
|
WebTabView* tab = dynamic_cast<WebTabView*>(fTabContainerView->TabAt(
|
||||||
|
TabForView(containedView)));
|
||||||
|
if (tab)
|
||||||
|
tab->SetIcon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabManager::SetCloseButtonsAvailable(bool available)
|
||||||
|
{
|
||||||
|
if (available == fController->CloseButtonsAvailable())
|
||||||
|
return;
|
||||||
|
fController->SetCloseButtonsAvailable(available);
|
||||||
|
fTabContainerView->Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TAB_MANAGER_H
|
||||||
|
#define TAB_MANAGER_H
|
||||||
|
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <TabView.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TAB_CHANGED = 'tcha',
|
||||||
|
CLOSE_TAB = 'cltb'
|
||||||
|
};
|
||||||
|
|
||||||
|
class BBitmap;
|
||||||
|
class BCardLayout;
|
||||||
|
class BGroupView;
|
||||||
|
class BMenu;
|
||||||
|
class TabContainerGroup;
|
||||||
|
class TabContainerView;
|
||||||
|
class TabManagerController;
|
||||||
|
|
||||||
|
class TabManager {
|
||||||
|
public:
|
||||||
|
TabManager(const BMessenger& target,
|
||||||
|
BMessage* newTabMessage);
|
||||||
|
virtual ~TabManager();
|
||||||
|
|
||||||
|
void SetTarget(const BMessenger& target);
|
||||||
|
const BMessenger& Target() const;
|
||||||
|
|
||||||
|
#if INTEGRATE_MENU_INTO_TAB_BAR
|
||||||
|
BMenu* Menu() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
BView* TabGroup() const;
|
||||||
|
BView* GetTabContainerView() const;
|
||||||
|
BView* ContainerView() const;
|
||||||
|
|
||||||
|
BView* ViewForTab(int32 tabIndex) const;
|
||||||
|
int32 TabForView(const BView* containedView) const;
|
||||||
|
bool HasView(const BView* containedView) const;
|
||||||
|
|
||||||
|
void SelectTab(int32 tabIndex);
|
||||||
|
void SelectTab(const BView* containedView);
|
||||||
|
int32 SelectedTabIndex() const;
|
||||||
|
void CloseTab(int32 tabIndex);
|
||||||
|
|
||||||
|
void AddTab(BView* view, const char* label,
|
||||||
|
int32 index = -1);
|
||||||
|
BView* RemoveTab(int32 index);
|
||||||
|
int32 CountTabs() const;
|
||||||
|
|
||||||
|
void SetTabLabel(int32 tabIndex, const char* label);
|
||||||
|
const BString& TabLabel(int32);
|
||||||
|
void SetTabIcon(const BView* containedView,
|
||||||
|
const BBitmap* icon);
|
||||||
|
void SetCloseButtonsAvailable(bool available);
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if INTEGRATE_MENU_INTO_TAB_BAR
|
||||||
|
BMenu* fMenu;
|
||||||
|
#endif
|
||||||
|
TabContainerGroup* fTabContainerGroup;
|
||||||
|
TabContainerView* fTabContainerView;
|
||||||
|
BView* fContainerView;
|
||||||
|
BCardLayout* fCardLayout;
|
||||||
|
TabManagerController* fController;
|
||||||
|
|
||||||
|
BMessenger fTarget;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TAB_MANAGER_H
|
||||||
@@ -0,0 +1,365 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Rene Gollent <[email protected]>
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TabView.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <Bitmap.h>
|
||||||
|
#include <Button.h>
|
||||||
|
#include <CardLayout.h>
|
||||||
|
#include <ControlLook.h>
|
||||||
|
#include <GroupView.h>
|
||||||
|
#include <MenuBar.h>
|
||||||
|
#include <SpaceLayoutItem.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "TabContainerView.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TabView
|
||||||
|
|
||||||
|
|
||||||
|
TabView::TabView()
|
||||||
|
:
|
||||||
|
fContainerView(NULL),
|
||||||
|
fLayoutItem(new TabLayoutItem(this)),
|
||||||
|
fLabel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabView::~TabView()
|
||||||
|
{
|
||||||
|
// The layout item is deleted for us by the layout which contains it.
|
||||||
|
if (!fContainerView)
|
||||||
|
delete fLayoutItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabView::MinSize()
|
||||||
|
{
|
||||||
|
BSize size(MaxSize());
|
||||||
|
size.width = 60.0f;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabView::PreferredSize()
|
||||||
|
{
|
||||||
|
return MaxSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabView::MaxSize()
|
||||||
|
{
|
||||||
|
float extra = be_control_look->DefaultLabelSpacing();
|
||||||
|
float labelWidth = 300.0f;
|
||||||
|
return BSize(labelWidth, _LabelHeight() + extra);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
BRect frame(fLayoutItem->Frame());
|
||||||
|
if (fIsFront) {
|
||||||
|
// Extend the front tab outward left/right in order to merge
|
||||||
|
// the frames of adjacent tabs.
|
||||||
|
if (!fIsFirst)
|
||||||
|
frame.left--;
|
||||||
|
if (!fIsLast)
|
||||||
|
frame.right++;
|
||||||
|
|
||||||
|
frame.bottom++;
|
||||||
|
}
|
||||||
|
DrawBackground(fContainerView, frame, updateRect, fIsFirst, fIsLast,
|
||||||
|
fIsFront);
|
||||||
|
if (fIsFront) {
|
||||||
|
frame.top += 3.0f;
|
||||||
|
if (!fIsFirst)
|
||||||
|
frame.left++;
|
||||||
|
if (!fIsLast)
|
||||||
|
frame.right--;
|
||||||
|
} else
|
||||||
|
frame.top += 6.0f;
|
||||||
|
float spacing = be_control_look->DefaultLabelSpacing();
|
||||||
|
frame.InsetBy(spacing, spacing / 2);
|
||||||
|
DrawContents(fContainerView, frame, updateRect, fIsFirst, fIsLast,
|
||||||
|
fIsFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::DrawBackground(BView* owner, BRect frame, const BRect& updateRect,
|
||||||
|
bool isFirst, bool isLast, bool isFront)
|
||||||
|
{
|
||||||
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
uint32 borders = BControlLook::B_TOP_BORDER
|
||||||
|
| BControlLook::B_BOTTOM_BORDER;
|
||||||
|
if (isFirst)
|
||||||
|
borders |= BControlLook::B_LEFT_BORDER;
|
||||||
|
if (isLast)
|
||||||
|
borders |= BControlLook::B_RIGHT_BORDER;
|
||||||
|
if (isFront) {
|
||||||
|
be_control_look->DrawActiveTab(owner, frame, updateRect, base,
|
||||||
|
0, borders);
|
||||||
|
} else {
|
||||||
|
be_control_look->DrawInactiveTab(owner, frame, updateRect, base,
|
||||||
|
0, borders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::DrawContents(BView* owner, BRect frame, const BRect& updateRect,
|
||||||
|
bool isFirst, bool isLast, bool isFront)
|
||||||
|
{
|
||||||
|
rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
be_control_look->DrawLabel(owner, fLabel.String(), frame, updateRect,
|
||||||
|
base, 0, BAlignment(B_ALIGN_LEFT, B_ALIGN_MIDDLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::MouseDown(BPoint where, uint32 buttons)
|
||||||
|
{
|
||||||
|
fContainerView->SelectTab(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::MouseUp(BPoint where)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::SetIsFront(bool isFront)
|
||||||
|
{
|
||||||
|
Update(fIsFirst, fIsLast, isFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabView::IsFront() const
|
||||||
|
{
|
||||||
|
return fIsFront;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::SetIsLast(bool isLast)
|
||||||
|
{
|
||||||
|
Update(fIsFirst, isLast, fIsFront);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::Update(bool isFirst, bool isLast, bool isFront)
|
||||||
|
{
|
||||||
|
if (fIsFirst == isFirst && fIsLast == isLast && fIsFront == isFront)
|
||||||
|
return;
|
||||||
|
fIsFirst = isFirst;
|
||||||
|
fIsLast = isLast;
|
||||||
|
fIsFront = isFront;
|
||||||
|
|
||||||
|
fLayoutItem->InvalidateContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::SetContainerView(TabContainerView* containerView)
|
||||||
|
{
|
||||||
|
fContainerView = containerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabContainerView*
|
||||||
|
TabView::ContainerView() const
|
||||||
|
{
|
||||||
|
return fContainerView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BLayoutItem*
|
||||||
|
TabView::LayoutItem() const
|
||||||
|
{
|
||||||
|
return fLayoutItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabView::SetLabel(const char* label)
|
||||||
|
{
|
||||||
|
if (fLabel == label)
|
||||||
|
return;
|
||||||
|
fLabel = label;
|
||||||
|
fLayoutItem->InvalidateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const BString&
|
||||||
|
TabView::Label() const
|
||||||
|
{
|
||||||
|
return fLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
TabView::Frame() const
|
||||||
|
{
|
||||||
|
return fLayoutItem->Frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
TabView::_LabelHeight() const
|
||||||
|
{
|
||||||
|
font_height fontHeight;
|
||||||
|
fContainerView->GetFontHeight(&fontHeight);
|
||||||
|
return ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - TabLayoutItem
|
||||||
|
|
||||||
|
|
||||||
|
TabLayoutItem::TabLayoutItem(TabView* parent)
|
||||||
|
:
|
||||||
|
fParent(parent),
|
||||||
|
fVisible(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TabLayoutItem::IsVisible()
|
||||||
|
{
|
||||||
|
return fVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabLayoutItem::SetVisible(bool visible)
|
||||||
|
{
|
||||||
|
if (fVisible == visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fVisible = visible;
|
||||||
|
|
||||||
|
InvalidateContainer();
|
||||||
|
fParent->ContainerView()->InvalidateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BRect
|
||||||
|
TabLayoutItem::Frame()
|
||||||
|
{
|
||||||
|
return fFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabLayoutItem::SetFrame(BRect frame)
|
||||||
|
{
|
||||||
|
BRect dirty = fFrame;
|
||||||
|
fFrame = frame;
|
||||||
|
dirty = dirty | fFrame;
|
||||||
|
InvalidateContainer(dirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BView*
|
||||||
|
TabLayoutItem::View()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabLayoutItem::BaseMinSize()
|
||||||
|
{
|
||||||
|
return fParent->MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabLayoutItem::BaseMaxSize()
|
||||||
|
{
|
||||||
|
return fParent->MaxSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
TabLayoutItem::BasePreferredSize()
|
||||||
|
{
|
||||||
|
return fParent->PreferredSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAlignment
|
||||||
|
TabLayoutItem::BaseAlignment()
|
||||||
|
{
|
||||||
|
return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TabView*
|
||||||
|
TabLayoutItem::Parent() const
|
||||||
|
{
|
||||||
|
return fParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabLayoutItem::InvalidateContainer()
|
||||||
|
{
|
||||||
|
InvalidateContainer(Frame());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TabLayoutItem::InvalidateContainer(BRect frame)
|
||||||
|
{
|
||||||
|
// Invalidate more than necessary, to help the TabContainerView
|
||||||
|
// redraw the parts outside any tabs...
|
||||||
|
frame.bottom++;
|
||||||
|
frame.right++;
|
||||||
|
fParent->ContainerView()->Invalidate(frame);
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Stephan Aßmus <[email protected]>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||||
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef TAB_VIEW_H
|
||||||
|
#define TAB_VIEW_H
|
||||||
|
|
||||||
|
#include <AbstractLayoutItem.h>
|
||||||
|
#include <Rect.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BMessage;
|
||||||
|
class BView;
|
||||||
|
class TabContainerView;
|
||||||
|
class TabLayoutItem;
|
||||||
|
|
||||||
|
|
||||||
|
class TabView {
|
||||||
|
public:
|
||||||
|
TabView();
|
||||||
|
virtual ~TabView();
|
||||||
|
|
||||||
|
virtual BSize MinSize();
|
||||||
|
virtual BSize PreferredSize();
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
|
||||||
|
void Draw(BRect updateRect);
|
||||||
|
virtual void DrawBackground(BView* owner, BRect frame,
|
||||||
|
const BRect& updateRect, bool isFirst,
|
||||||
|
bool isLast, bool isFront);
|
||||||
|
virtual void DrawContents(BView* owner, BRect frame,
|
||||||
|
const BRect& updateRect, bool isFirst,
|
||||||
|
bool isLast, bool isFront);
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, uint32 buttons);
|
||||||
|
virtual void MouseUp(BPoint where);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
|
||||||
|
void SetIsFront(bool isFront);
|
||||||
|
bool IsFront() const;
|
||||||
|
void SetIsLast(bool isLast);
|
||||||
|
virtual void Update(bool isFirst, bool isLast,
|
||||||
|
bool isFront);
|
||||||
|
|
||||||
|
BLayoutItem* LayoutItem() const;
|
||||||
|
void SetContainerView(
|
||||||
|
TabContainerView* containerView);
|
||||||
|
TabContainerView* ContainerView() const;
|
||||||
|
|
||||||
|
void SetLabel(const char* label);
|
||||||
|
const BString& Label() const;
|
||||||
|
|
||||||
|
BRect Frame() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float _LabelHeight() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TabContainerView* fContainerView;
|
||||||
|
TabLayoutItem* fLayoutItem;
|
||||||
|
|
||||||
|
BString fLabel;
|
||||||
|
|
||||||
|
bool fIsFirst;
|
||||||
|
bool fIsLast;
|
||||||
|
bool fIsFront;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TabLayoutItem : public BAbstractLayoutItem {
|
||||||
|
public:
|
||||||
|
TabLayoutItem(TabView* parent);
|
||||||
|
|
||||||
|
virtual bool IsVisible();
|
||||||
|
virtual void SetVisible(bool visible);
|
||||||
|
|
||||||
|
virtual BRect Frame();
|
||||||
|
virtual void SetFrame(BRect frame);
|
||||||
|
|
||||||
|
virtual BView* View();
|
||||||
|
|
||||||
|
virtual BSize BaseMinSize();
|
||||||
|
virtual BSize BaseMaxSize();
|
||||||
|
virtual BSize BasePreferredSize();
|
||||||
|
virtual BAlignment BaseAlignment();
|
||||||
|
|
||||||
|
TabView* Parent() const;
|
||||||
|
void InvalidateContainer();
|
||||||
|
void InvalidateContainer(BRect frame);
|
||||||
|
private:
|
||||||
|
TabView* fParent;
|
||||||
|
BRect fFrame;
|
||||||
|
bool fVisible;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TAB_VIEW_H
|
||||||
@@ -634,20 +634,20 @@ ConfirmChangeIfWellKnownDirectory(const BEntry *entry,
|
|||||||
if (DirectoryMatchesOrContains(entry, B_SYSTEM_DIRECTORY)) {
|
if (DirectoryMatchesOrContains(entry, B_SYSTEM_DIRECTORY)) {
|
||||||
warning.SetTo(
|
warning.SetTo(
|
||||||
B_TRANSLATE("If you %ifYouDoAction the system folder or its "
|
B_TRANSLATE("If you %ifYouDoAction the system folder or its "
|
||||||
"contents, you won't be able to boot %osName! Are you sure you "
|
"contents, you won't be able to boot %osName!\n\nAre you sure you "
|
||||||
"want to do this? To %toDoAction the system folder or its "
|
"want to do this?\n\nTo %toDoAction the system folder or its "
|
||||||
"contents anyway, hold down the Shift key and click "
|
"contents anyway, hold down the Shift key and click "
|
||||||
"\"%toConfirmAction\"."));
|
"\"%toConfirmAction\"."));
|
||||||
} else if (DirectoryMatches(entry, B_COMMON_DIRECTORY)) {
|
} else if (DirectoryMatches(entry, B_COMMON_DIRECTORY)) {
|
||||||
warning.SetTo(
|
warning.SetTo(
|
||||||
B_TRANSLATE("If you %ifYouDoAction the common folder, %osName "
|
B_TRANSLATE("If you %ifYouDoAction the common folder, %osName "
|
||||||
"may not behave properly! Are you sure you want to do this? "
|
"may not behave properly!\n\nAre you sure you want to do this?\n\n"
|
||||||
"To %toDoAction the common folder anyway, hold down the "
|
"To %toDoAction the common folder anyway, hold down the "
|
||||||
"Shift key and click \"%toConfirmAction\"."));
|
"Shift key and click \"%toConfirmAction\"."));
|
||||||
} else if (DirectoryMatches(entry, B_USER_DIRECTORY)) {
|
} else if (DirectoryMatches(entry, B_USER_DIRECTORY)) {
|
||||||
warning .SetTo(
|
warning .SetTo(
|
||||||
B_TRANSLATE("If you %ifYouDoAction the home folder, %osName "
|
B_TRANSLATE("If you %ifYouDoAction the home folder, %osName "
|
||||||
"may not behave properly! Are you sure you want to do this? "
|
"may not behave properly!\n\nAre you sure you want to do this?\n\n"
|
||||||
"To %toDoAction the home folder anyway, hold down the "
|
"To %toDoAction the home folder anyway, hold down the "
|
||||||
"Shift key and click \"%toConfirmAction\"."));
|
"Shift key and click \"%toConfirmAction\"."));
|
||||||
} else if (DirectoryMatchesOrContains(entry, B_USER_CONFIG_DIRECTORY)
|
} else if (DirectoryMatchesOrContains(entry, B_USER_CONFIG_DIRECTORY)
|
||||||
@@ -659,24 +659,21 @@ ConfirmChangeIfWellKnownDirectory(const BEntry *entry,
|
|||||||
B_COMMON_SETTINGS_DIRECTORY)) {
|
B_COMMON_SETTINGS_DIRECTORY)) {
|
||||||
warning.SetTo(
|
warning.SetTo(
|
||||||
B_TRANSLATE("If you %ifYouDoAction the mime settings, "
|
B_TRANSLATE("If you %ifYouDoAction the mime settings, "
|
||||||
"%osName may not behave properly! Are you sure you want to "
|
"%osName may not behave properly!\n\nAre you sure you want to "
|
||||||
"do this? To %toDoAction the mime settings anyway, click "
|
"do this?"));
|
||||||
"\"%toConfirmAction\"."));
|
|
||||||
requireOverride = false;
|
requireOverride = false;
|
||||||
} else if (DirectoryMatches(entry, B_USER_CONFIG_DIRECTORY)) {
|
} else if (DirectoryMatches(entry, B_USER_CONFIG_DIRECTORY)) {
|
||||||
warning.SetTo(
|
warning.SetTo(
|
||||||
B_TRANSLATE("If you %ifYouDoAction the config folder, %osName "
|
B_TRANSLATE("If you %ifYouDoAction the config folder, %osName "
|
||||||
"may not behave properly! Are you sure you want to do this? "
|
"may not behave properly!\n\nAre you sure you want to do "
|
||||||
"To %toDoAction the config folder anyway, click "
|
"this?"));
|
||||||
"\"%toConfirmAction\"."));
|
|
||||||
requireOverride = false;
|
requireOverride = false;
|
||||||
} else if (DirectoryMatches(entry, B_USER_SETTINGS_DIRECTORY)
|
} else if (DirectoryMatches(entry, B_USER_SETTINGS_DIRECTORY)
|
||||||
|| DirectoryMatches(entry, B_COMMON_SETTINGS_DIRECTORY)) {
|
|| DirectoryMatches(entry, B_COMMON_SETTINGS_DIRECTORY)) {
|
||||||
warning.SetTo(
|
warning.SetTo(
|
||||||
B_TRANSLATE("If you %ifYouDoAction the settings folder, "
|
B_TRANSLATE("If you %ifYouDoAction the settings folder, "
|
||||||
"%osName may not behave properly! Are you sure you want to "
|
"%osName may not behave properly!\n\nAre you sure you want to "
|
||||||
"do this? To %toDoAction the settings folder anyway, click "
|
"do this?"));
|
||||||
"\"%toConfirmAction\"."));
|
|
||||||
requireOverride = false;
|
requireOverride = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -681,8 +681,8 @@ OpenWithPoseView::OpenSelection(BPose *pose, int32 *)
|
|||||||
if (!fIterator->GenericFilesOnly()) {
|
if (!fIterator->GenericFilesOnly()) {
|
||||||
BString warning(B_TRANSLATE(
|
BString warning(B_TRANSLATE(
|
||||||
"The application \"%appname\" does not support the type of "
|
"The application \"%appname\" does not support the type of "
|
||||||
"document you are about to open. Are you sure you want to "
|
"document you are about to open.\nAre you sure you want to "
|
||||||
"proceed? If you know that the application supports the "
|
"proceed?\n\nIf you know that the application supports the "
|
||||||
"document type, you should contact the publisher of the "
|
"document type, you should contact the publisher of the "
|
||||||
"application and ask them to update their application to list "
|
"application and ask them to update their application to list "
|
||||||
"the type of your document as supported."));
|
"the type of your document as supported."));
|
||||||
|
|||||||
Reference in New Issue
Block a user