1 /* 2 * Copyright 2004-2010, 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 */ 11 12 #include "DateTimeView.h" 13 #include "AnalogClock.h" 14 #include "DateTimeEdit.h" 15 #include "TimeMessages.h" 16 #include "TimeWindow.h" 17 18 #include <CalendarView.h> 19 #include <Catalog.h> 20 #include <CheckBox.h> 21 #include <DateTime.h> 22 #include <Entry.h> 23 #include <File.h> 24 #include <FindDirectory.h> 25 #include <Message.h> 26 #include <Path.h> 27 #include <RadioButton.h> 28 #include <String.h> 29 #include <StringView.h> 30 #include <Window.h> 31 32 #include <time.h> 33 34 #include <syscalls.h> 35 36 #undef B_TRANSLATE_CONTEXT 37 #define B_TRANSLATE_CONTEXT "Time" 38 39 40 using BPrivate::BCalendarView; 41 using BPrivate::BDateTime; 42 using BPrivate::B_LOCAL_TIME; 43 44 45 DateTimeView::DateTimeView(BRect frame) 46 : BView(frame, "dateTimeView", B_FOLLOW_NONE, B_WILL_DRAW 47 | B_NAVIGABLE_JUMP), 48 fGmtTime(NULL), 49 fUseGmtTime(false), 50 fInitialized(false), 51 fSystemTimeAtStart(system_time()) 52 { 53 _ReadRTCSettings(); 54 _InitView(); 55 56 // record the current time to enable revert. 57 time(&fTimeAtStart); 58 } 59 60 61 DateTimeView::~DateTimeView() 62 { 63 _WriteRTCSettings(); 64 } 65 66 67 void 68 DateTimeView::AttachedToWindow() 69 { 70 if (Parent()) 71 SetViewColor(Parent()->ViewColor()); 72 73 if (!fInitialized) { 74 fInitialized = true; 75 76 fCalendarView->SetTarget(this); 77 } 78 } 79 80 81 void 82 DateTimeView::Draw(BRect /*updateRect*/) 83 { 84 rgb_color viewcolor = ViewColor(); 85 rgb_color dark = tint_color(viewcolor, B_DARKEN_4_TINT); 86 rgb_color light = tint_color(viewcolor, B_LIGHTEN_MAX_TINT); 87 88 // draw a separator line 89 BRect bounds(Bounds()); 90 BPoint start(bounds.Width() / 2.0f, bounds.top + 5.0f); 91 BPoint end(bounds.Width() / 2.0, bounds.bottom - 5.0f); 92 93 BeginLineArray(2); 94 AddLine(start, end, dark); 95 start.x++; 96 end.x++; 97 AddLine(start, end, light); 98 EndLineArray(); 99 100 fTimeEdit->Draw(bounds); 101 fDateEdit->Draw(bounds); 102 } 103 104 105 void 106 DateTimeView::MessageReceived(BMessage* message) 107 { 108 int32 change; 109 switch (message->what) { 110 case B_OBSERVER_NOTICE_CHANGE: 111 message->FindInt32(B_OBSERVE_WHAT_CHANGE, &change); 112 switch (change) { 113 case H_TM_CHANGED: 114 _UpdateDateTime(message); 115 break; 116 117 default: 118 BView::MessageReceived(message); 119 break; 120 } 121 break; 122 123 case kDayChanged: 124 { 125 BMessage msg(*message); 126 msg.what = H_USER_CHANGE; 127 msg.AddBool("time", false); 128 Window()->PostMessage(&msg); 129 break; 130 } 131 132 case kRTCUpdate: 133 fUseGmtTime = fGmtTime->Value() == B_CONTROL_ON; 134 _UpdateGmtSettings(); 135 break; 136 137 case kMsgRevert: 138 _Revert(); 139 break; 140 141 case kChangeTimeFinished: 142 if (fClock->IsChangingTime()) 143 fTimeEdit->MakeFocus(false); 144 fClock->ChangeTimeFinished(); 145 break; 146 147 default: 148 BView::MessageReceived(message); 149 break; 150 } 151 } 152 153 154 bool 155 DateTimeView::CheckCanRevert() 156 { 157 // check GMT vs Local setting 158 bool enable = fUseGmtTime != fOldUseGmtTime; 159 160 // check for changed time 161 time_t unchangedNow = fTimeAtStart + _PrefletUptime(); 162 time_t changedNow; 163 time(&changedNow); 164 165 return enable || (changedNow != unchangedNow); 166 } 167 168 169 void 170 DateTimeView::_Revert() 171 { 172 // Set the clock and calendar as they were at launch time + 173 // time elapsed since application launch. 174 175 fUseGmtTime = fOldUseGmtTime; 176 _UpdateGmtSettings(); 177 178 if (fUseGmtTime) 179 fGmtTime->SetValue(B_CONTROL_ON); 180 else 181 fLocalTime->SetValue(B_CONTROL_ON); 182 183 time_t timeNow = fTimeAtStart + _PrefletUptime(); 184 struct tm result; 185 struct tm* timeInfo; 186 timeInfo = localtime_r(&timeNow, &result); 187 188 BDateTime dateTime = BDateTime::CurrentDateTime(B_LOCAL_TIME); 189 BTime time = dateTime.Time(); 190 BDate date = dateTime.Date(); 191 time.SetTime(timeInfo->tm_hour, timeInfo->tm_min, timeInfo->tm_sec % 60); 192 date.SetDate(timeInfo->tm_year + 1900, timeInfo->tm_mon + 1, 193 timeInfo->tm_mday); 194 dateTime.SetTime(time); 195 dateTime.SetDate(date); 196 197 set_real_time_clock(dateTime.Time_t()); 198 } 199 200 201 time_t 202 DateTimeView::_PrefletUptime() const 203 { 204 return (time_t)((system_time() - fSystemTimeAtStart) / 1000000); 205 } 206 207 208 void 209 DateTimeView::_InitView() 210 { 211 font_height fontHeight; 212 be_plain_font->GetHeight(&fontHeight); 213 float textHeight = fontHeight.descent + fontHeight.ascent 214 + fontHeight.leading + 6.0; // 6px border 215 216 // left side 217 BRect bounds = Bounds(); 218 bounds.InsetBy(10.0, 10.0); 219 bounds.top += textHeight + 10.0; 220 221 fCalendarView = new BCalendarView(bounds, "calendar"); 222 fCalendarView->SetWeekNumberHeaderVisible(false); 223 fCalendarView->ResizeToPreferred(); 224 fCalendarView->SetSelectionMessage(new BMessage(kDayChanged)); 225 fCalendarView->SetInvocationMessage(new BMessage(kDayChanged)); 226 227 bounds.top -= textHeight + 10.0; 228 bounds.bottom = bounds.top + textHeight; 229 bounds.right = fCalendarView->Frame().right; 230 231 fDateEdit = new TDateEdit(bounds, "dateEdit", 3); 232 AddChild(fDateEdit); 233 AddChild(fCalendarView); 234 235 // right side, 2px extra for separator 236 bounds.OffsetBy(bounds.Width() + 22.0, 0.0); 237 fTimeEdit = new TTimeEdit(bounds, "timeEdit", 4); 238 AddChild(fTimeEdit); 239 240 bounds = fCalendarView->Frame(); 241 bounds.OffsetBy(bounds.Width() + 22.0, 0.0); 242 243 fClock = new TAnalogClock(bounds, "analogClock"); 244 AddChild(fClock); 245 BTime time(BTime::CurrentTime(B_LOCAL_TIME)); 246 fClock->SetTime(time.Hour(), time.Minute(), time.Second()); 247 248 // clock radio buttons 249 bounds.top = fClock->Frame().bottom + 10.0; 250 BStringView* text = new BStringView(bounds, "clockSetTo", 251 B_TRANSLATE("Clock set to:")); 252 AddChild(text); 253 text->ResizeToPreferred(); 254 255 bounds.left += 10.0f; 256 bounds.top = text->Frame().bottom; 257 fLocalTime = new BRadioButton(bounds, "localTime", 258 B_TRANSLATE("Local time"), new BMessage(kRTCUpdate)); 259 AddChild(fLocalTime); 260 fLocalTime->ResizeToPreferred(); 261 262 bounds.left = fLocalTime->Frame().right + 10.0; 263 fGmtTime = new BRadioButton(bounds, "greenwichMeanTime", 264 B_TRANSLATE("GMT"), new BMessage(kRTCUpdate)); 265 AddChild(fGmtTime); 266 fGmtTime->ResizeToPreferred(); 267 268 if (fUseGmtTime) 269 fGmtTime->SetValue(B_CONTROL_ON); 270 else 271 fLocalTime->SetValue(B_CONTROL_ON); 272 273 fOldUseGmtTime = fUseGmtTime; 274 275 ResizeTo(fClock->Frame().right + 10.0, fGmtTime->Frame().bottom + 10.0); 276 } 277 278 279 void 280 DateTimeView::_ReadRTCSettings() 281 { 282 BPath path; 283 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 284 return; 285 286 path.Append("RTC_time_settings"); 287 288 BEntry entry(path.Path()); 289 if (entry.Exists()) { 290 BFile file(&entry, B_READ_ONLY); 291 if (file.InitCheck() == B_OK) { 292 char buffer[6]; 293 file.Read(buffer, 6); 294 if (strncmp(buffer, "gmt", 3) == 0) 295 fUseGmtTime = true; 296 } 297 } 298 } 299 300 301 void 302 DateTimeView::_WriteRTCSettings() 303 { 304 BPath path; 305 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK) 306 return; 307 308 path.Append("RTC_time_settings"); 309 310 BFile file(path.Path(), B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); 311 if (file.InitCheck() == B_OK) { 312 if (fUseGmtTime) 313 file.Write("gmt", 3); 314 else 315 file.Write("local", 5); 316 } 317 } 318 319 320 void 321 DateTimeView::_UpdateGmtSettings() 322 { 323 _WriteRTCSettings(); 324 325 _kern_set_real_time_clock_is_gmt(fUseGmtTime); 326 } 327 328 329 void 330 DateTimeView::_UpdateDateTime(BMessage* message) 331 { 332 int32 day; 333 int32 month; 334 int32 year; 335 if (message->FindInt32("month", &month) == B_OK 336 && message->FindInt32("day", &day) == B_OK 337 && message->FindInt32("year", &year) == B_OK) { 338 fDateEdit->SetDate(year, month, day); 339 fCalendarView->SetDate(year, month, day); 340 } 341 342 int32 hour; 343 int32 minute; 344 int32 second; 345 if (message->FindInt32("hour", &hour) == B_OK 346 && message->FindInt32("minute", &minute) == B_OK 347 && message->FindInt32("second", &second) == B_OK) { 348 fClock->SetTime(hour, minute, second); 349 fTimeEdit->SetTime(hour, minute, second); 350 } 351 } 352