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_TRANSLATE_CONTEXT 39 #define B_TRANSLATE_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