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