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