xref: /haiku/src/preferences/time/DateTimeView.cpp (revision 19ae20e67e91fc09cc9fc5c0e60e21e24e7a53eb)
1 /*
2  * Copyright 2004-2011, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Andrew McCall <mccall@@digitalparadise.co.uk>
7  *		Mike Berg <mike@berg-net.us>
8  *		Julun <host.haiku@gmx.de>
9  *		Philippe Saint-Pierre <stpere@gmail.com>
10  *		Hamish Morrison <hamish@lavabit.com>
11  */
12 
13 #include "DateTimeView.h"
14 
15 #include <time.h>
16 #include <syscalls.h>
17 
18 #include <Box.h>
19 #include <CalendarView.h>
20 #include <Catalog.h>
21 #include <CheckBox.h>
22 #include <ControlLook.h>
23 #include <DateTime.h>
24 #include <Entry.h>
25 #include <File.h>
26 #include <FindDirectory.h>
27 #include <Message.h>
28 #include <Path.h>
29 #include <StringView.h>
30 #include <Window.h>
31 
32 #include "AnalogClock.h"
33 #include "DateTimeEdit.h"
34 #include "TimeMessages.h"
35 #include "TimeWindow.h"
36 
37 
38 #undef B_TRANSLATE_CONTEXT
39 #define B_TRANSLATE_CONTEXT "Time"
40 
41 
42 using BPrivate::BCalendarView;
43 using BPrivate::BDateTime;
44 using BPrivate::B_LOCAL_TIME;
45 
46 
47 DateTimeView::DateTimeView(const char* name)
48 	:
49 	BGroupView(name, B_HORIZONTAL, 5),
50 	fInitialized(false),
51 	fSystemTimeAtStart(system_time())
52 {
53 	_InitView();
54 
55 	// record the current time to enable revert.
56 	time(&fTimeAtStart);
57 }
58 
59 
60 DateTimeView::~DateTimeView()
61 {
62 }
63 
64 
65 void
66 DateTimeView::AttachedToWindow()
67 {
68 	if (Parent())
69 		SetViewColor(Parent()->ViewColor());
70 
71 	if (!fInitialized) {
72 		fInitialized = true;
73 
74 		fCalendarView->SetTarget(this);
75 	}
76 
77 	_NotifyClockSettingChanged();
78 }
79 
80 
81 void
82 DateTimeView::MessageReceived(BMessage* message)
83 {
84 	int32 change;
85 	switch (message->what) {
86 		case B_OBSERVER_NOTICE_CHANGE:
87 			message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change);
88 			switch (change) {
89 				case H_TM_CHANGED:
90 					_UpdateDateTime(message);
91 					break;
92 
93 				default:
94 					BView::MessageReceived(message);
95 					break;
96 			}
97 			break;
98 
99 		case kDayChanged:
100 		{
101 			BMessage msg(*message);
102 			msg.what = H_USER_CHANGE;
103 			msg.AddBool("time", false);
104 			Window()->PostMessage(&msg);
105 			break;
106 		}
107 
108 		case kMsgRevert:
109 			_Revert();
110 			break;
111 
112 		case kChangeTimeFinished:
113 			if (fClock->IsChangingTime())
114 				fTimeEdit->MakeFocus(false);
115 			fClock->ChangeTimeFinished();
116 			break;
117 
118 		case kRTCUpdate:
119 			break;
120 
121 		default:
122 			BView::MessageReceived(message);
123 			break;
124 	}
125 }
126 
127 
128 bool
129 DateTimeView::CheckCanRevert()
130 {
131 	// check for changed time
132 	time_t unchangedNow = fTimeAtStart + _PrefletUptime();
133 	time_t changedNow;
134 	time(&changedNow);
135 
136 	return changedNow != unchangedNow;
137 }
138 
139 
140 void
141 DateTimeView::_Revert()
142 {
143 	// Set the clock and calendar as they were at launch time +
144 	// time elapsed since application launch.
145 
146 	time_t timeNow = fTimeAtStart + _PrefletUptime();
147 	struct tm result;
148 	struct tm* timeInfo;
149 	timeInfo = localtime_r(&timeNow, &result);
150 
151 	BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME);
152 	BTime time = dateTime.Time();
153 	BDate date = dateTime.Date();
154 	time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60);
155 	date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1,
156 		timeInfo->tm_mday);
157 	dateTime.SetTime(time);
158 	dateTime.SetDate(date);
159 
160 	set_real_time_clock(dateTime.Time_t());
161 }
162 
163 
164 time_t
165 DateTimeView::_PrefletUptime() const
166 {
167 	return (time_t)((system_time() - fSystemTimeAtStart) / 1000000);
168 }
169 
170 
171 void
172 DateTimeView::_InitView()
173 {
174 	fCalendarView = new BCalendarView("calendar");
175 	fCalendarView->SetWeekNumberHeaderVisible(false);
176 	fCalendarView->SetSelectionMessage(new BMessage(kDayChanged));
177 	fCalendarView->SetInvocationMessage(new BMessage(kDayChanged));
178 
179 	fDateEdit = new TDateEdit("dateEdit", 3);
180 	fTimeEdit = new TTimeEdit("timeEdit", 4);
181 	fClock = new TAnalogClock("analogClock");
182 
183 	BTime time(BTime::CurrentTime(B_LOCAL_TIME));
184 	fClock->SetTime(time.Hour(), time.Minute(), time.Second());
185 
186 	BBox* divider = new BBox(BRect(0, 0, 1, 1),
187 		B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
188 		B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER);
189 	divider->SetExplicitMaxSize(BSize(1, B_SIZE_UNLIMITED));
190 
191 	const float kInset = be_control_look->DefaultItemSpacing();
192 	BLayoutBuilder::Group<>(this)
193 		.AddGroup(B_VERTICAL, kInset / 2)
194 			.Add(fDateEdit)
195 			.Add(fCalendarView)
196 		.End()
197 		.Add(divider)
198 		.AddGroup(B_VERTICAL, 0)
199 			.Add(fTimeEdit)
200 			.Add(fClock)
201 		.End()
202 		.SetInsets(kInset, kInset, kInset, kInset);
203 }
204 
205 
206 void
207 DateTimeView::_UpdateDateTime(BMessage* message)
208 {
209 	int32 day;
210 	int32 month;
211 	int32 year;
212 	if (message->FindInt32("month", &month) == B_OK
213 		&& message->FindInt32("day", &day) == B_OK
214 		&& message->FindInt32("year", &year) == B_OK) {
215 		static int32 lastDay;
216 		static int32 lastMonth;
217 		static int32 lastYear;
218 		if (day != lastDay || month != lastMonth || year != lastYear) {
219 			fDateEdit->SetDate(year, month, day);
220 			fCalendarView->SetDate(year, month, day);
221 			lastDay = day;
222 			lastMonth = month;
223 			lastYear = year;
224 		}
225 	}
226 
227 	int32 hour;
228 	int32 minute;
229 	int32 second;
230 	if (message->FindInt32("hour", &hour) == B_OK
231 		&& message->FindInt32("minute", &minute) == B_OK
232 		&& message->FindInt32("second", &second) == B_OK) {
233 		fClock->SetTime(hour, minute, second);
234 		fTimeEdit->SetTime(hour, minute, second);
235 	}
236 }
237 
238 
239 void
240 DateTimeView::_NotifyClockSettingChanged()
241 {
242 	BMessage msg(kMsgClockSettingChanged);
243 	Window()->PostMessage(&msg);
244 }
245 
246