xref: /haiku/src/preferences/time/DateTimeView.cpp (revision 310930fd9e9f40c29bc5f77e323fb0c7733c12d9)
1e4289a54SKarsten Heimrich /*
2e4289a54SKarsten Heimrich  * Copyright 2004-2007, Haiku, Inc. All Rights Reserved.
3e4289a54SKarsten Heimrich  * Distributed under the terms of the MIT License.
4e4289a54SKarsten Heimrich  *
5e4289a54SKarsten Heimrich  * Authors:
6e4289a54SKarsten Heimrich  *		Andrew McCall <mccall@@digitalparadise.co.uk>
7e4289a54SKarsten Heimrich  *		Mike Berg <mike@berg-net.us>
8e4289a54SKarsten Heimrich  *		Julun <host.haiku@gmx.de>
91cae077aSStephan Aßmus  *		Philippe Saint-Pierre <stpere@gmail.com>
10e4289a54SKarsten Heimrich  */
11e4289a54SKarsten Heimrich 
12e4289a54SKarsten Heimrich #include "DateTimeView.h"
13e4289a54SKarsten Heimrich #include "AnalogClock.h"
14e4289a54SKarsten Heimrich #include "CalendarView.h"
15e4289a54SKarsten Heimrich #include "DateTimeEdit.h"
16e4289a54SKarsten Heimrich #include "TimeMessages.h"
171cae077aSStephan Aßmus #include "DateTime.h"
18*310930fdSStephan Aßmus #include "TimeWindow.h"
19e4289a54SKarsten Heimrich 
20e4289a54SKarsten Heimrich 
21e4289a54SKarsten Heimrich #include <CheckBox.h>
22e4289a54SKarsten Heimrich #include <Entry.h>
23e4289a54SKarsten Heimrich #include <File.h>
24e4289a54SKarsten Heimrich #include <FindDirectory.h>
25e4289a54SKarsten Heimrich #include <Message.h>
26e4289a54SKarsten Heimrich #include <Path.h>
27e4289a54SKarsten Heimrich #include <RadioButton.h>
28e4289a54SKarsten Heimrich #include <String.h>
29e4289a54SKarsten Heimrich #include <StringView.h>
30e4289a54SKarsten Heimrich #include <Window.h>
311cae077aSStephan Aßmus #include <time.h>
32e4289a54SKarsten Heimrich 
33e4289a54SKarsten Heimrich 
34e4289a54SKarsten Heimrich #ifdef HAIKU_TARGET_PLATFORM_HAIKU
35e4289a54SKarsten Heimrich #	include <syscalls.h>
36e4289a54SKarsten Heimrich #else
37a22279faSAxel Dörfler extern "C" void _kset_tzfilename_(const char *name, size_t length, bool isGMT);
38e4289a54SKarsten Heimrich #	define _kern_set_tzfilename _kset_tzfilename_
39e4289a54SKarsten Heimrich #endif
40e4289a54SKarsten Heimrich 
41e4289a54SKarsten Heimrich 
42e4289a54SKarsten Heimrich DateTimeView::DateTimeView(BRect frame)
4385b69a94SKarsten Heimrich 	: BView(frame, "dateTimeView", B_FOLLOW_NONE, B_WILL_DRAW | B_NAVIGABLE_JUMP),
44e4289a54SKarsten Heimrich 	  fGmtTime(NULL),
4585b69a94SKarsten Heimrich 	  fUseGmtTime(false),
461cae077aSStephan Aßmus 	  fInitialized(false),
471cae077aSStephan Aßmus 	  fSystemTimeAtStart(system_time())
48e4289a54SKarsten Heimrich {
49e4289a54SKarsten Heimrich 	_ReadRTCSettings();
5085b69a94SKarsten Heimrich 	_InitView();
511cae077aSStephan Aßmus 
521cae077aSStephan Aßmus 	// record the current time to enable revert.
531cae077aSStephan Aßmus 	time(&fTimeAtStart);
54e4289a54SKarsten Heimrich }
55e4289a54SKarsten Heimrich 
56e4289a54SKarsten Heimrich 
57e4289a54SKarsten Heimrich DateTimeView::~DateTimeView()
58e4289a54SKarsten Heimrich {
59e4289a54SKarsten Heimrich 	_WriteRTCSettings();
60e4289a54SKarsten Heimrich }
61e4289a54SKarsten Heimrich 
62e4289a54SKarsten Heimrich 
63e4289a54SKarsten Heimrich void
64e4289a54SKarsten Heimrich DateTimeView::AttachedToWindow()
65e4289a54SKarsten Heimrich {
66e4289a54SKarsten Heimrich 	if (Parent())
67e4289a54SKarsten Heimrich 		SetViewColor(Parent()->ViewColor());
68e4289a54SKarsten Heimrich 
69e4289a54SKarsten Heimrich 	if (!fInitialized) {
70e4289a54SKarsten Heimrich 		fInitialized = true;
7185b69a94SKarsten Heimrich 
7285b69a94SKarsten Heimrich 		fCalendarView->SetTarget(this);
73e4289a54SKarsten Heimrich 	}
74e4289a54SKarsten Heimrich }
75e4289a54SKarsten Heimrich 
76e4289a54SKarsten Heimrich 
77e4289a54SKarsten Heimrich void
78e4289a54SKarsten Heimrich DateTimeView::Draw(BRect /*updateRect*/)
79e4289a54SKarsten Heimrich {
80e4289a54SKarsten Heimrich 	rgb_color viewcolor = ViewColor();
81e4289a54SKarsten Heimrich 	rgb_color dark = tint_color(viewcolor, B_DARKEN_4_TINT);
82e4289a54SKarsten Heimrich 	rgb_color light = tint_color(viewcolor, B_LIGHTEN_MAX_TINT);
83e4289a54SKarsten Heimrich 
84e4289a54SKarsten Heimrich 	//draw a separator line
85e4289a54SKarsten Heimrich 	BRect bounds(Bounds());
8685b69a94SKarsten Heimrich 	BPoint start(bounds.Width() / 2.0f, bounds.top + 5.0f);
8785b69a94SKarsten Heimrich 	BPoint end(bounds.Width() / 2.0, bounds.bottom - 5.0f);
88e4289a54SKarsten Heimrich 
89e4289a54SKarsten Heimrich 	BeginLineArray(2);
90e4289a54SKarsten Heimrich 		AddLine(start, end, dark);
91e4289a54SKarsten Heimrich 		start.x++;
92e4289a54SKarsten Heimrich 		end.x++;
93e4289a54SKarsten Heimrich 		AddLine(start, end, light);
94e4289a54SKarsten Heimrich 	EndLineArray();
95e4289a54SKarsten Heimrich 
96e4289a54SKarsten Heimrich 	fTimeEdit->Draw(bounds);
97e4289a54SKarsten Heimrich 	fDateEdit->Draw(bounds);
98e4289a54SKarsten Heimrich }
99e4289a54SKarsten Heimrich 
100e4289a54SKarsten Heimrich 
101e4289a54SKarsten Heimrich void
102e4289a54SKarsten Heimrich DateTimeView::MessageReceived(BMessage *message)
103e4289a54SKarsten Heimrich {
104e4289a54SKarsten Heimrich 	int32 change;
105e4289a54SKarsten Heimrich 	switch(message->what) {
106e4289a54SKarsten Heimrich 		case B_OBSERVER_NOTICE_CHANGE:
107e4289a54SKarsten Heimrich 			message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change);
108e4289a54SKarsten Heimrich 			switch(change) {
109e4289a54SKarsten Heimrich 				case H_TM_CHANGED:
110e4289a54SKarsten Heimrich 					_UpdateDateTime(message);
111e4289a54SKarsten Heimrich 					break;
112e4289a54SKarsten Heimrich 
113e4289a54SKarsten Heimrich 				default:
114e4289a54SKarsten Heimrich 					BView::MessageReceived(message);
115e4289a54SKarsten Heimrich 					break;
116e4289a54SKarsten Heimrich 			}
117e4289a54SKarsten Heimrich 		break;
118e4289a54SKarsten Heimrich 
119e4289a54SKarsten Heimrich 		case kDayChanged:
120e4289a54SKarsten Heimrich 		{
121e4289a54SKarsten Heimrich 			BMessage msg(*message);
122e4289a54SKarsten Heimrich 			msg.what = H_USER_CHANGE;
123e4289a54SKarsten Heimrich 			msg.AddBool("time", false);
124e4289a54SKarsten Heimrich 			Window()->PostMessage(&msg);
1251cae077aSStephan Aßmus 			break;
1261cae077aSStephan Aßmus 		}
127e4289a54SKarsten Heimrich 
128e4289a54SKarsten Heimrich 		case kRTCUpdate:
1291cae077aSStephan Aßmus 			fUseGmtTime = fGmtTime->Value() == B_CONTROL_ON;
130e4289a54SKarsten Heimrich 			_UpdateGmtSettings();
1311cae077aSStephan Aßmus 			break;
1321cae077aSStephan Aßmus 
1331cae077aSStephan Aßmus 		case kMsgRevert:
1341cae077aSStephan Aßmus 			_Revert();
135e4289a54SKarsten Heimrich 			break;
136e4289a54SKarsten Heimrich 
137e4289a54SKarsten Heimrich 		default:
138e4289a54SKarsten Heimrich 			BView::MessageReceived(message);
139e4289a54SKarsten Heimrich 			break;
140e4289a54SKarsten Heimrich 	}
141e4289a54SKarsten Heimrich }
142e4289a54SKarsten Heimrich 
143e4289a54SKarsten Heimrich 
144*310930fdSStephan Aßmus bool
1451cae077aSStephan Aßmus DateTimeView::CheckCanRevert()
1461cae077aSStephan Aßmus {
1471cae077aSStephan Aßmus 	// check GMT vs Local setting
1481cae077aSStephan Aßmus 	bool enable = fUseGmtTime != fOldUseGmtTime;
1491cae077aSStephan Aßmus 
1501cae077aSStephan Aßmus 	// check for changed time
1511cae077aSStephan Aßmus 	time_t unchangedNow = fTimeAtStart + _PrefletUptime();
1521cae077aSStephan Aßmus 	time_t changedNow;
1531cae077aSStephan Aßmus 	time(&changedNow);
1541cae077aSStephan Aßmus 
155*310930fdSStephan Aßmus 	return enable || (changedNow != unchangedNow);
1561cae077aSStephan Aßmus }
1571cae077aSStephan Aßmus 
1581cae077aSStephan Aßmus 
1591cae077aSStephan Aßmus void
1601cae077aSStephan Aßmus DateTimeView::_Revert()
1611cae077aSStephan Aßmus {
1621cae077aSStephan Aßmus 	// Set the clock and calendar as they were at launch time +
1631cae077aSStephan Aßmus 	// time ellapsed since application launch.
1641cae077aSStephan Aßmus 
1651cae077aSStephan Aßmus 	fUseGmtTime = fOldUseGmtTime;
1661cae077aSStephan Aßmus 	_UpdateGmtSettings();
1671cae077aSStephan Aßmus 
1681cae077aSStephan Aßmus 	if (fUseGmtTime)
1691cae077aSStephan Aßmus 		fGmtTime->SetValue(B_CONTROL_ON);
1701cae077aSStephan Aßmus 	else
1711cae077aSStephan Aßmus 		fLocalTime->SetValue(B_CONTROL_ON);
1721cae077aSStephan Aßmus 
1731cae077aSStephan Aßmus 	time_t timeNow = fTimeAtStart + _PrefletUptime();
1741cae077aSStephan Aßmus 	struct tm result;
1751cae077aSStephan Aßmus 	struct tm* timeInfo;
1761cae077aSStephan Aßmus 	timeInfo = localtime_r(&timeNow, &result);
1771cae077aSStephan Aßmus 
1781cae077aSStephan Aßmus 	BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME);
1791cae077aSStephan Aßmus 	BTime time = dateTime.Time();
1801cae077aSStephan Aßmus 	BDate date = dateTime.Date();
1811cae077aSStephan Aßmus 	time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60);
1821cae077aSStephan Aßmus 	date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1,
1831cae077aSStephan Aßmus 		timeInfo->tm_mday);
1841cae077aSStephan Aßmus 	dateTime.SetTime(time);
1851cae077aSStephan Aßmus 	dateTime.SetDate(date);
1861cae077aSStephan Aßmus 
1871cae077aSStephan Aßmus 	set_real_time_clock(dateTime.Time_t());
1881cae077aSStephan Aßmus }
1891cae077aSStephan Aßmus 
1901cae077aSStephan Aßmus 
1911cae077aSStephan Aßmus time_t
1921cae077aSStephan Aßmus DateTimeView::_PrefletUptime() const
1931cae077aSStephan Aßmus {
1941cae077aSStephan Aßmus 	return (time_t)((system_time() - fSystemTimeAtStart) / 1000000);
1951cae077aSStephan Aßmus }
1961cae077aSStephan Aßmus 
1971cae077aSStephan Aßmus 
1981cae077aSStephan Aßmus void
199e4289a54SKarsten Heimrich DateTimeView::_InitView()
200e4289a54SKarsten Heimrich {
201e4289a54SKarsten Heimrich 	font_height fontHeight;
202e4289a54SKarsten Heimrich 	be_plain_font->GetHeight(&fontHeight);
20385b69a94SKarsten Heimrich 	float textHeight = fontHeight.descent + fontHeight.ascent
20485b69a94SKarsten Heimrich 		+ fontHeight.leading + 6.0;	// 6px border
205e4289a54SKarsten Heimrich 
206e4289a54SKarsten Heimrich 	// left side
20785b69a94SKarsten Heimrich 	BRect bounds = Bounds();
20885b69a94SKarsten Heimrich 	bounds.InsetBy(10.0, 10.0);
20985b69a94SKarsten Heimrich 	bounds.top += textHeight + 10.0;
210e4289a54SKarsten Heimrich 
21185b69a94SKarsten Heimrich 	fCalendarView = new BCalendarView(bounds, "calendar");
212e4289a54SKarsten Heimrich 	fCalendarView->SetWeekNumberHeaderVisible(false);
21385b69a94SKarsten Heimrich 	fCalendarView->ResizeToPreferred();
214e4289a54SKarsten Heimrich 	fCalendarView->SetSelectionMessage(new BMessage(kDayChanged));
215e4289a54SKarsten Heimrich 	fCalendarView->SetInvocationMessage(new BMessage(kDayChanged));
216e4289a54SKarsten Heimrich 
21785b69a94SKarsten Heimrich 	bounds.top -= textHeight + 10.0;
21885b69a94SKarsten Heimrich 	bounds.bottom = bounds.top + textHeight;
21985b69a94SKarsten Heimrich 	bounds.right = fCalendarView->Frame().right;
220e4289a54SKarsten Heimrich 
22185b69a94SKarsten Heimrich 	fDateEdit = new TDateEdit(bounds, "dateEdit", 3);
22285b69a94SKarsten Heimrich 	AddChild(fDateEdit);
22385b69a94SKarsten Heimrich 	AddChild(fCalendarView);
22485b69a94SKarsten Heimrich 
22585b69a94SKarsten Heimrich 	// right side, 2px extra for separator
22685b69a94SKarsten Heimrich 	bounds.OffsetBy(bounds.Width() + 22.0, 0.0);
22785b69a94SKarsten Heimrich 	fTimeEdit = new TTimeEdit(bounds, "timeEdit", 4);
228e4289a54SKarsten Heimrich 	AddChild(fTimeEdit);
229e4289a54SKarsten Heimrich 
23085b69a94SKarsten Heimrich 	bounds = fCalendarView->Frame();
23185b69a94SKarsten Heimrich 	bounds.OffsetBy(bounds.Width() + 22.0, 0.0);
232e4289a54SKarsten Heimrich 
23385b69a94SKarsten Heimrich 	fClock = new TAnalogClock(bounds, "analogClock");
234e4289a54SKarsten Heimrich 	AddChild(fClock);
235e4289a54SKarsten Heimrich 
236e4289a54SKarsten Heimrich 	// clock radio buttons
23785b69a94SKarsten Heimrich 	bounds.top = fClock->Frame().bottom + 10.0;
23885b69a94SKarsten Heimrich 	BStringView *text = new BStringView(bounds, "clockSetTo", "Clock set to:");
239e4289a54SKarsten Heimrich 	AddChild(text);
240e4289a54SKarsten Heimrich 	text->ResizeToPreferred();
241e4289a54SKarsten Heimrich 
24285b69a94SKarsten Heimrich 	bounds.left += 10.0f;
24385b69a94SKarsten Heimrich 	bounds.top = text->Frame().bottom;
24485b69a94SKarsten Heimrich 	fLocalTime = new BRadioButton(bounds, "localTime", "Local Time",
245e4289a54SKarsten Heimrich 		new BMessage(kRTCUpdate));
246e4289a54SKarsten Heimrich 	AddChild(fLocalTime);
247e4289a54SKarsten Heimrich 	fLocalTime->ResizeToPreferred();
248e4289a54SKarsten Heimrich 
24985b69a94SKarsten Heimrich 	bounds.left = fLocalTime->Frame().right + 10.0;
25085b69a94SKarsten Heimrich 	fGmtTime = new BRadioButton(bounds, "greenwichMeanTime", "GMT",
25185b69a94SKarsten Heimrich 		new BMessage(kRTCUpdate));
252e4289a54SKarsten Heimrich 	AddChild(fGmtTime);
253e4289a54SKarsten Heimrich 	fGmtTime->ResizeToPreferred();
254e4289a54SKarsten Heimrich 
25585b69a94SKarsten Heimrich 	if (fUseGmtTime)
256e4289a54SKarsten Heimrich 		fGmtTime->SetValue(B_CONTROL_ON);
25785b69a94SKarsten Heimrich 	else
25885b69a94SKarsten Heimrich 		fLocalTime->SetValue(B_CONTROL_ON);
25985b69a94SKarsten Heimrich 
2601cae077aSStephan Aßmus 	fOldUseGmtTime = fUseGmtTime;
2611cae077aSStephan Aßmus 
26285b69a94SKarsten Heimrich 	ResizeTo(fClock->Frame().right + 10.0, fGmtTime->Frame().bottom + 10.0);
263e4289a54SKarsten Heimrich }
264e4289a54SKarsten Heimrich 
265e4289a54SKarsten Heimrich 
266e4289a54SKarsten Heimrich void
267e4289a54SKarsten Heimrich DateTimeView::_ReadRTCSettings()
268e4289a54SKarsten Heimrich {
269e4289a54SKarsten Heimrich 	BPath path;
270e4289a54SKarsten Heimrich 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
271e4289a54SKarsten Heimrich 		return;
272e4289a54SKarsten Heimrich 
273e4289a54SKarsten Heimrich 	path.Append("RTC_time_settings");
274e4289a54SKarsten Heimrich 
275e4289a54SKarsten Heimrich 	BEntry entry(path.Path());
276e4289a54SKarsten Heimrich 	if (entry.Exists()) {
27785b69a94SKarsten Heimrich 		BFile file(&entry, B_READ_ONLY);
278e4289a54SKarsten Heimrich 		if (file.InitCheck() == B_OK) {
27985b69a94SKarsten Heimrich 			char buffer[6];
28085b69a94SKarsten Heimrich 			file.Read(buffer, 6);
28185b69a94SKarsten Heimrich 			if (strncmp(buffer, "gmt", 3) == 0)
28285b69a94SKarsten Heimrich 				fUseGmtTime = true;
283e4289a54SKarsten Heimrich 		}
28485b69a94SKarsten Heimrich 	} else
28585b69a94SKarsten Heimrich 		_UpdateGmtSettings();
286e4289a54SKarsten Heimrich }
287e4289a54SKarsten Heimrich 
288e4289a54SKarsten Heimrich 
289e4289a54SKarsten Heimrich void
290e4289a54SKarsten Heimrich DateTimeView::_WriteRTCSettings()
291e4289a54SKarsten Heimrich {
292e4289a54SKarsten Heimrich 	BPath path;
293e4289a54SKarsten Heimrich 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
294e4289a54SKarsten Heimrich 		return;
295e4289a54SKarsten Heimrich 
296e4289a54SKarsten Heimrich 	path.Append("RTC_time_settings");
297e4289a54SKarsten Heimrich 
298e4289a54SKarsten Heimrich 	BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
299e4289a54SKarsten Heimrich 	if (file.InitCheck() == B_OK) {
30085b69a94SKarsten Heimrich 		if (fUseGmtTime)
301e4289a54SKarsten Heimrich 			file.Write("gmt", 3);
30285b69a94SKarsten Heimrich 		else
30385b69a94SKarsten Heimrich 			file.Write("local", 5);
304e4289a54SKarsten Heimrich 	}
305e4289a54SKarsten Heimrich }
306e4289a54SKarsten Heimrich 
307e4289a54SKarsten Heimrich 
308e4289a54SKarsten Heimrich void
309e4289a54SKarsten Heimrich DateTimeView::_UpdateGmtSettings()
310e4289a54SKarsten Heimrich {
311e4289a54SKarsten Heimrich 	_WriteRTCSettings();
312e4289a54SKarsten Heimrich 
313e4289a54SKarsten Heimrich 	BPath path;
314e4289a54SKarsten Heimrich 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
315e4289a54SKarsten Heimrich 		return;
316e4289a54SKarsten Heimrich 
317e4289a54SKarsten Heimrich 	path.Append("timezone");
318e4289a54SKarsten Heimrich 	BEntry entry(path.Path(), true);
319e4289a54SKarsten Heimrich 
320e4289a54SKarsten Heimrich 	if (!entry.Exists())
321e4289a54SKarsten Heimrich 		return;
322e4289a54SKarsten Heimrich 
323e4289a54SKarsten Heimrich 	entry.GetPath(&path);
324e4289a54SKarsten Heimrich 
325e4289a54SKarsten Heimrich 	// take the existing timezone and set it's gmt use
32685b69a94SKarsten Heimrich 	_kern_set_tzfilename(path.Path(), B_PATH_NAME_LENGTH, fUseGmtTime);
327e4289a54SKarsten Heimrich }
328e4289a54SKarsten Heimrich 
329e4289a54SKarsten Heimrich 
330e4289a54SKarsten Heimrich void
331e4289a54SKarsten Heimrich DateTimeView::_UpdateDateTime(BMessage *message)
332e4289a54SKarsten Heimrich {
333e4289a54SKarsten Heimrich 	int32 day;
334e4289a54SKarsten Heimrich 	int32 month;
335e4289a54SKarsten Heimrich 	int32 year;
336e4289a54SKarsten Heimrich 	if (message->FindInt32("month", &month) == B_OK
337e4289a54SKarsten Heimrich 		&& message->FindInt32("day", &day) == B_OK
338e4289a54SKarsten Heimrich 		&& message->FindInt32("year", &year) == B_OK)
339e4289a54SKarsten Heimrich 	{
340e4289a54SKarsten Heimrich 		fDateEdit->SetDate(year, month, day);
341e4289a54SKarsten Heimrich 		fCalendarView->SetDate(year, month, day);
342e4289a54SKarsten Heimrich 	}
343e4289a54SKarsten Heimrich 
344e4289a54SKarsten Heimrich 	int32 hour;
345e4289a54SKarsten Heimrich 	int32 minute;
346e4289a54SKarsten Heimrich 	int32 second;
347e4289a54SKarsten Heimrich 	if (message->FindInt32("hour", &hour) == B_OK
348e4289a54SKarsten Heimrich 		&& message->FindInt32("minute", &minute) == B_OK
349e4289a54SKarsten Heimrich 		&& message->FindInt32("second", &second) == B_OK)
350e4289a54SKarsten Heimrich 	{
351e4289a54SKarsten Heimrich 		fClock->SetTime(hour, minute, second);
35285b69a94SKarsten Heimrich 		fTimeEdit->SetTime(hour, minute, second);
353e4289a54SKarsten Heimrich 	}
354e4289a54SKarsten Heimrich }
355