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> - 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.
|
||||
# <entries> - The entries of the archive file one is interested in. 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
|
||||
if [ IsOptionalHaikuImagePackageAdded CARootCertificates ] {
|
||||
InstallOptionalHaikuImagePackage cert-2012-05-02.zip
|
||||
: $(baseURL)/cert-2012-05-02.zip
|
||||
InstallOptionalHaikuImagePackage cert-2012-07-04.zip
|
||||
: $(baseURL)/cert-2012-07-04.zip
|
||||
: common data ssl ;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,5 +59,6 @@ HaikuSubInclude terminal ;
|
||||
HaikuSubInclude text_search ;
|
||||
HaikuSubInclude tracker ;
|
||||
HaikuSubInclude tv ;
|
||||
HaikuSubInclude webpositive ;
|
||||
HaikuSubInclude webwatch ;
|
||||
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 <superstippi@gmx.de>
|
||||
*
|
||||
* 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 <rene@gollent.com>
|
||||
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* 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 <superstippi@gmx.de>
|
||||
*
|
||||
* 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 <rene@gollent.com>
|
||||
* Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
|
||||
*
|
||||
* 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 <superstippi@gmx.de>
|
||||
*
|
||||
* 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)) {
|
||||
warning.SetTo(
|
||||
B_TRANSLATE("If you %ifYouDoAction the system folder or its "
|
||||
"contents, you won't be able to boot %osName! Are you sure you "
|
||||
"want to do this? To %toDoAction the system folder or its "
|
||||
"contents, you won't be able to boot %osName!\n\nAre you sure you "
|
||||
"want to do this?\n\nTo %toDoAction the system folder or its "
|
||||
"contents anyway, hold down the Shift key and click "
|
||||
"\"%toConfirmAction\"."));
|
||||
} else if (DirectoryMatches(entry, B_COMMON_DIRECTORY)) {
|
||||
warning.SetTo(
|
||||
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 "
|
||||
"Shift key and click \"%toConfirmAction\"."));
|
||||
} else if (DirectoryMatches(entry, B_USER_DIRECTORY)) {
|
||||
warning .SetTo(
|
||||
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 "
|
||||
"Shift key and click \"%toConfirmAction\"."));
|
||||
} else if (DirectoryMatchesOrContains(entry, B_USER_CONFIG_DIRECTORY)
|
||||
@@ -659,24 +659,21 @@ ConfirmChangeIfWellKnownDirectory(const BEntry *entry,
|
||||
B_COMMON_SETTINGS_DIRECTORY)) {
|
||||
warning.SetTo(
|
||||
B_TRANSLATE("If you %ifYouDoAction the mime settings, "
|
||||
"%osName may not behave properly! Are you sure you want to "
|
||||
"do this? To %toDoAction the mime settings anyway, click "
|
||||
"\"%toConfirmAction\"."));
|
||||
"%osName may not behave properly!\n\nAre you sure you want to "
|
||||
"do this?"));
|
||||
requireOverride = false;
|
||||
} else if (DirectoryMatches(entry, B_USER_CONFIG_DIRECTORY)) {
|
||||
warning.SetTo(
|
||||
B_TRANSLATE("If you %ifYouDoAction the config folder, %osName "
|
||||
"may not behave properly! Are you sure you want to do this? "
|
||||
"To %toDoAction the config folder anyway, click "
|
||||
"\"%toConfirmAction\"."));
|
||||
"may not behave properly!\n\nAre you sure you want to do "
|
||||
"this?"));
|
||||
requireOverride = false;
|
||||
} else if (DirectoryMatches(entry, B_USER_SETTINGS_DIRECTORY)
|
||||
|| DirectoryMatches(entry, B_COMMON_SETTINGS_DIRECTORY)) {
|
||||
warning.SetTo(
|
||||
B_TRANSLATE("If you %ifYouDoAction the settings folder, "
|
||||
"%osName may not behave properly! Are you sure you want to "
|
||||
"do this? To %toDoAction the settings folder anyway, click "
|
||||
"\"%toConfirmAction\"."));
|
||||
"%osName may not behave properly!\n\nAre you sure you want to "
|
||||
"do this?"));
|
||||
requireOverride = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,8 +681,8 @@ OpenWithPoseView::OpenSelection(BPose *pose, int32 *)
|
||||
if (!fIterator->GenericFilesOnly()) {
|
||||
BString warning(B_TRANSLATE(
|
||||
"The application \"%appname\" does not support the type of "
|
||||
"document you are about to open. Are you sure you want to "
|
||||
"proceed? If you know that the application supports the "
|
||||
"document you are about to open.\nAre you sure you want to "
|
||||
"proceed?\n\nIf you know that the application supports the "
|
||||
"document type, you should contact the publisher of the "
|
||||
"application and ask them to update their application to list "
|
||||
"the type of your document as supported."));
|
||||
|
||||
Reference in New Issue
Block a user