xref: /haiku/src/preferences/time/DateTimeView.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
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_TRANSLATION_CONTEXT
39 #define B_TRANSLATION_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 
78 
79 void
80 DateTimeView::MessageReceived(BMessage* message)
81 {
82 	int32 change;
83 	switch (message->what) {
84 		case B_OBSERVER_NOTICE_CHANGE:
85 			message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change);
86 			switch (change) {
87 				case H_TM_CHANGED:
88 					_UpdateDateTime(message);
89 					break;
90 
91 				default:
92 					BView::MessageReceived(message);
93 					break;
94 			}
95 			break;
96 
97 		case kDayChanged:
98 		{
99 			BMessage msg(*message);
100 			msg.what = H_USER_CHANGE;
101 			msg.AddBool("time", false);
102 			Window()->PostMessage(&msg);
103 			break;
104 		}
105 
106 		case kMsgRevert:
107 			_Revert();
108 			break;
109 
110 		case kChangeTimeFinished:
111 			if (fClock->IsChangingTime())
112 				fTimeEdit->MakeFocus(false);
113 			fClock->ChangeTimeFinished();
114 			break;
115 
116 		case kRTCUpdate:
117 			break;
118 
119 		default:
120 			BView::MessageReceived(message);
121 			break;
122 	}
123 }
124 
125 
126 bool
127 DateTimeView::CheckCanRevert()
128 {
129 	// check for changed time
130 	time_t unchangedNow = fTimeAtStart + _PrefletUptime();
131 	time_t changedNow;
132 	time(&changedNow);
133 
134 	return changedNow != unchangedNow;
135 }
136 
137 
138 void
139 DateTimeView::_Revert()
140 {
141 	// Set the clock and calendar as they were at launch time +
142 	// time elapsed since application launch.
143 
144 	time_t timeNow = fTimeAtStart + _PrefletUptime();
145 	struct tm result;
146 	struct tm* timeInfo;
147 	timeInfo = localtime_r(&timeNow, &result);
148 
149 	BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME);
150 	BTime time = dateTime.Time();
151 	BDate date = dateTime.Date();
152 	time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60);
153 	date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1,
154 		timeInfo->tm_mday);
155 	dateTime.SetTime(time);
156 	dateTime.SetDate(date);
157 
158 	set_real_time_clock(dateTime.Time_t());
159 }
160 
161 
162 time_t
163 DateTimeView::_PrefletUptime() const
164 {
165 	return (time_t)((system_time() - fSystemTimeAtStart) / 1000000);
166 }
167 
168 
169 void
170 DateTimeView::_InitView()
171 {
172 	fCalendarView = new BCalendarView("calendar");
173 	fCalendarView->SetWeekNumberHeaderVisible(false);
174 	fCalendarView->SetSelectionMessage(new BMessage(kDayChanged));
175 	fCalendarView->SetInvocationMessage(new BMessage(kDayChanged));
176 
177 	fDateEdit = new TDateEdit("dateEdit", 3);
178 	fTimeEdit = new TTimeEdit("timeEdit", 4);
179 	fClock = new TAnalogClock("analogClock");
180 
181 	BTime time(BTime::CurrentTime(B_LOCAL_TIME));
182 	fClock->SetTime(time.Hour(), time.Minute(), time.Second());
183 
184 	BBox* divider = new BBox(BRect(0, 0, 1, 1),
185 		B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
186 		B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER);
187 	divider->SetExplicitMaxSize(BSize(1, B_SIZE_UNLIMITED));
188 
189 	const float kInset = be_control_look->DefaultItemSpacing();
190 	BLayoutBuilder::Group<>(this)
191 		.AddGroup(B_VERTICAL, kInset / 2)
192 			.Add(fDateEdit)
193 			.Add(fCalendarView)
194 		.End()
195 		.Add(divider)
196 		.AddGroup(B_VERTICAL, 0)
197 			.Add(fTimeEdit)
198 			.Add(fClock)
199 		.End()
200 		.SetInsets(kInset, kInset, kInset, kInset);
201 }
202 
203 
204 void
205 DateTimeView::_UpdateDateTime(BMessage* message)
206 {
207 	int32 day;
208 	int32 month;
209 	int32 year;
210 	if (message->FindInt32("month", &month) == B_OK
211 		&& message->FindInt32("day", &day) == B_OK
212 		&& message->FindInt32("year", &year) == B_OK) {
213 		static int32 lastDay;
214 		static int32 lastMonth;
215 		static int32 lastYear;
216 		if (day != lastDay || month != lastMonth || year != lastYear) {
217 			fDateEdit->SetDate(year, month, day);
218 			fCalendarView->SetDate(year, month, day);
219 			lastDay = day;
220 			lastMonth = month;
221 			lastYear = year;
222 		}
223 	}
224 
225 	int32 hour;
226 	int32 minute;
227 	int32 second;
228 	if (message->FindInt32("hour", &hour) == B_OK
229 		&& message->FindInt32("minute", &minute) == B_OK
230 		&& message->FindInt32("second", &second) == B_OK) {
231 		fClock->SetTime(hour, minute, second);
232 		fTimeEdit->SetTime(hour, minute, second);
233 	}
234 }
235 
236