xref: /haiku/src/preferences/time/DateTimeView.cpp (revision c42868a015daa160e093679b2637b1cf9f0b26ba)
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 <LocaleRoster.h>
28 #include <Message.h>
29 #include <Path.h>
30 #include <StringView.h>
31 #include <Window.h>
32 
33 #include "AnalogClock.h"
34 #include "DateTimeEdit.h"
35 #include "TimeMessages.h"
36 #include "TimeWindow.h"
37 
38 
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "Time"
41 
42 
43 using BPrivate::BCalendarView;
44 using BPrivate::BDateTime;
45 using BPrivate::B_LOCAL_TIME;
46 
47 
48 DateTimeView::DateTimeView(const char* name)
49 	:
50 	BGroupView(name, B_HORIZONTAL, 5),
51 	fInitialized(false),
52 	fSystemTimeAtStart(system_time())
53 {
54 	_InitView();
55 
56 	// record the current time to enable revert.
57 	time(&fTimeAtStart);
58 }
59 
60 
61 DateTimeView::~DateTimeView()
62 {
63 }
64 
65 
66 void
67 DateTimeView::AttachedToWindow()
68 {
69 	AdoptParentColors();
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 B_LOCALE_CHANGED:
98 			fCalendarView->UpdateDayNameHeader();
99 			break;
100 
101 		case kDayChanged:
102 		{
103 			BMessage msg(*message);
104 			msg.what = H_USER_CHANGE;
105 			msg.AddBool("time", false);
106 			Window()->PostMessage(&msg);
107 			break;
108 		}
109 
110 		case kMsgRevert:
111 			_Revert();
112 			break;
113 
114 		case kChangeTimeFinished:
115 			if (fClock->IsChangingTime())
116 				fTimeEdit->MakeFocus(false);
117 			fClock->ChangeTimeFinished();
118 			break;
119 
120 		case kRTCUpdate:
121 			break;
122 
123 		default:
124 			BView::MessageReceived(message);
125 			break;
126 	}
127 }
128 
129 
130 bool
131 DateTimeView::CheckCanRevert()
132 {
133 	// check for changed time
134 	time_t unchangedNow = fTimeAtStart + _PrefletUptime();
135 	time_t changedNow;
136 	time(&changedNow);
137 
138 	return changedNow != unchangedNow;
139 }
140 
141 
142 void
143 DateTimeView::_Revert()
144 {
145 	// Set the clock and calendar as they were at launch time +
146 	// time elapsed since application launch.
147 
148 	time_t timeNow = fTimeAtStart + _PrefletUptime();
149 	struct tm result;
150 	struct tm* timeInfo;
151 	timeInfo = localtime_r(&timeNow, &result);
152 
153 	BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME);
154 	BTime time = dateTime.Time();
155 	BDate date = dateTime.Date();
156 	time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60);
157 	date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1,
158 		timeInfo->tm_mday);
159 	dateTime.SetTime(time);
160 	dateTime.SetDate(date);
161 
162 	set_real_time_clock(dateTime.Time_t());
163 }
164 
165 
166 time_t
167 DateTimeView::_PrefletUptime() const
168 {
169 	return (time_t)((system_time() - fSystemTimeAtStart) / 1000000);
170 }
171 
172 
173 void
174 DateTimeView::_InitView()
175 {
176 	fCalendarView = new BCalendarView("calendar");
177 	fCalendarView->SetWeekNumberHeaderVisible(false);
178 	fCalendarView->SetSelectionMessage(new BMessage(kDayChanged));
179 	fCalendarView->SetInvocationMessage(new BMessage(kDayChanged));
180 
181 	fDateEdit = new TDateEdit("dateEdit", 3);
182 	fTimeEdit = new TTimeEdit("timeEdit", 5);
183 	fClock = new TAnalogClock("analogClock");
184 
185 	BTime time(BTime::CurrentTime(B_LOCAL_TIME));
186 	fClock->SetTime(time.Hour(), time.Minute(), time.Second());
187 
188 	BBox* divider = new BBox(BRect(0, 0, 1, 1),
189 		B_EMPTY_STRING, B_FOLLOW_ALL_SIDES,
190 		B_WILL_DRAW | B_FRAME_EVENTS, B_FANCY_BORDER);
191 	divider->SetExplicitMaxSize(BSize(1, B_SIZE_UNLIMITED));
192 
193 	BLayoutBuilder::Group<>(this, B_HORIZONTAL, B_USE_DEFAULT_SPACING)
194 		.AddGroup(B_VERTICAL, B_USE_DEFAULT_SPACING)
195 			.Add(fDateEdit)
196 			.Add(fCalendarView)
197 		.End()
198 		.Add(divider)
199 		.AddGroup(B_VERTICAL)
200 			.Add(fTimeEdit)
201 			.Add(fClock)
202 		.End()
203 		.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
204 			B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING);
205 }
206 
207 
208 void
209 DateTimeView::_UpdateDateTime(BMessage* message)
210 {
211 	int32 day;
212 	int32 month;
213 	int32 year;
214 	if (message->FindInt32("month", &month) == B_OK
215 		&& message->FindInt32("day", &day) == B_OK
216 		&& message->FindInt32("year", &year) == B_OK) {
217 		static int32 lastDay;
218 		static int32 lastMonth;
219 		static int32 lastYear;
220 		if (day != lastDay || month != lastMonth || year != lastYear) {
221 			fDateEdit->SetDate(year, month, day);
222 			fCalendarView->SetDate(year, month, day);
223 			lastDay = day;
224 			lastMonth = month;
225 			lastYear = year;
226 		}
227 	}
228 
229 	int32 hour;
230 	int32 minute;
231 	int32 second;
232 	if (message->FindInt32("hour", &hour) == B_OK
233 		&& message->FindInt32("minute", &minute) == B_OK
234 		&& message->FindInt32("second", &second) == B_OK) {
235 		fClock->SetTime(hour, minute, second);
236 		fTimeEdit->SetTime(hour, minute, second);
237 	}
238 }
239 
240