root/src/preferences/time/ClockView.cpp
/*
 * Copyright 2004-2011, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              John Scipione <jscipione@gmail.com>
 */


#include "ClockView.h"

#include <Alignment.h>
#include <Box.h>
#include <Catalog.h>
#include <CheckBox.h>
#include <ControlLook.h>
#include <LayoutBuilder.h>
#include <Locale.h>
#include <Message.h>
#include <Messenger.h>
#include <RadioButton.h>
#include <SpaceLayoutItem.h>
#include <Window.h>

#include "TimeMessages.h"


static const char* kDeskbarSignature = "application/x-vnd.Be-TSKB";


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Time"


ClockView::ClockView(const char* name)
        :
        BView(name, 0),
        fCachedShowClock(B_CONTROL_ON),
        fCachedShowSeconds(B_CONTROL_OFF),
        fCachedShowDayOfWeek(B_CONTROL_OFF),
        fCachedShowTimeZone(B_CONTROL_OFF)
{
        fShowClock = new BCheckBox(B_TRANSLATE("Show clock in Deskbar"),
                new BMessage(kShowHideTime));
        fShowSeconds = new BCheckBox(B_TRANSLATE("Display time with seconds"),
                new BMessage(kShowSeconds));
        fShowDayOfWeek = new BCheckBox(B_TRANSLATE("Show day of week"),
                new BMessage(kShowDayOfWeek));
        fShowTimeZone = new BCheckBox(B_TRANSLATE("Show time zone"),
                new BMessage(kShowTimeZone));

        BView* view = BLayoutBuilder::Group<>(B_VERTICAL, 0)
                .SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET))
                .Add(fShowSeconds)
                .Add(fShowDayOfWeek)
                .Add(fShowTimeZone)
                .AddGlue()
                .SetInsets(B_USE_DEFAULT_SPACING)
                .View();

        BBox* showClockBox = new BBox("show clock box");
        showClockBox->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_TOP));
        showClockBox->SetLabel(fShowClock);
        showClockBox->AddChild(view);

        BLayoutBuilder::Group<>(this)
                .AddGroup(B_VERTICAL, 0)
                        .Add(showClockBox)
                .End()
                .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
                        B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING);
}


ClockView::~ClockView()
{
}


void
ClockView::AttachedToWindow()
{
        AdoptParentColors();

        fShowClock->SetTarget(this);
        fShowSeconds->SetTarget(this);
        fShowDayOfWeek->SetTarget(this);
        fShowTimeZone->SetTarget(this);

        // Disable these controls initially, they'll be enabled
        // when we get a response from Deskbar.
        fShowClock->SetEnabled(false);
        fShowSeconds->SetEnabled(false);
        fShowDayOfWeek->SetEnabled(false);
        fShowTimeZone->SetEnabled(false);

        // Ask Deskbar for current clock settings, it will reply
        // asynchronously in MesssageReceived() below.
        BMessenger* messenger = new BMessenger(kDeskbarSignature);
        BMessenger replyMessenger(this);
        BMessage* message = new BMessage(kGetClockSettings);
        messenger->SendMessage(message, replyMessenger);
}


void
ClockView::MessageReceived(BMessage* message)
{
        switch (message->what) {
                case kGetClockSettings:
                {
                        // Get current clock settings from Deskbar
                        bool showClock;
                        bool showSeconds;
                        bool showDayOfWeek;
                        bool showTimeZone;

                        if (message->FindBool("showSeconds", &showSeconds) == B_OK) {
                                fCachedShowSeconds = showSeconds
                                        ? B_CONTROL_ON : B_CONTROL_OFF;
                                fShowSeconds->SetValue(fCachedShowSeconds);
                                fShowSeconds->SetEnabled(true);
                        }

                        if (message->FindBool("showDayOfWeek", &showDayOfWeek) == B_OK) {
                                fCachedShowDayOfWeek = showDayOfWeek
                                        ? B_CONTROL_ON : B_CONTROL_OFF;
                                fShowDayOfWeek->SetValue(fCachedShowDayOfWeek);
                                fShowDayOfWeek->SetEnabled(true);
                        }

                        if (message->FindBool("showTimeZone", &showTimeZone) == B_OK) {
                                fCachedShowTimeZone = showTimeZone
                                        ? B_CONTROL_ON : B_CONTROL_OFF;
                                fShowTimeZone->SetValue(fCachedShowTimeZone);
                                fShowTimeZone->SetEnabled(true);
                        }

                        // do this one last because it might disable the others
                        if (message->FindBool("showClock", &showClock) == B_OK) {
                                fCachedShowClock = showClock ? B_CONTROL_ON : B_CONTROL_OFF;
                                fShowClock->SetValue(fCachedShowClock);
                                fShowClock->SetEnabled(true);
                                fShowSeconds->SetEnabled(showClock);
                                fShowDayOfWeek->SetEnabled(showClock);
                                fShowTimeZone->SetEnabled(showClock);
                        }
                        break;
                }

                case kShowHideTime:
                {
                        bool showClock;
                        if (message->FindBool("showClock", &showClock) == B_OK) {
                                // message originated from Deskbar, handle special
                                fShowClock->SetValue(showClock ? B_CONTROL_ON : B_CONTROL_OFF);
                                fShowSeconds->SetEnabled(showClock);
                                fShowDayOfWeek->SetEnabled(showClock);
                                fShowTimeZone->SetEnabled(showClock);

                                Window()->PostMessage(kMsgChange);
                                break;
                                        // don't fall through
                        }
                        showClock = fShowClock->Value() == B_CONTROL_ON;
                        fShowSeconds->SetEnabled(showClock);
                        fShowDayOfWeek->SetEnabled(showClock);
                        fShowTimeZone->SetEnabled(showClock);
                }
                // fall-through
                case kShowSeconds:
                case kShowDayOfWeek:
                case kShowTimeZone:
                {
                        BMessenger* messenger = new BMessenger(kDeskbarSignature);
                        messenger->SendMessage(message);

                        Window()->PostMessage(kMsgChange);

                        break;
                }

                case kMsgRevert:
                        _Revert();
                        break;

                default:
                        BView::MessageReceived(message);
                        break;
        }
}


bool
ClockView::CheckCanRevert()
{
        return fShowClock->Value() != fCachedShowClock
                || fShowSeconds->Value() != fCachedShowSeconds
                || fShowDayOfWeek->Value() != fCachedShowDayOfWeek
                || fShowTimeZone->Value() != fCachedShowTimeZone;
}


void
ClockView::_Revert()
{
        if (fShowClock->Value() != fCachedShowClock) {
                fShowClock->SetValue(fCachedShowClock);
                fShowClock->Invoke();
        }

        if (fShowSeconds->Value() != fCachedShowSeconds) {
                fShowSeconds->SetValue(fCachedShowSeconds);
                fShowSeconds->Invoke();
        }

        if (fShowDayOfWeek->Value() != fCachedShowDayOfWeek) {
                fShowDayOfWeek->SetValue(fCachedShowDayOfWeek);
                fShowDayOfWeek->Invoke();
        }

        if (fShowTimeZone->Value() != fCachedShowTimeZone) {
                fShowTimeZone->SetValue(fCachedShowTimeZone);
                fShowTimeZone->Invoke();
        }
}