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