Calendar: Implement new mockup
https://bugzilla.gnome.org/show_bug.cgi?id=632109 Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
parent
4c64920f45
commit
885b6ffaef
@ -66,6 +66,10 @@ GJS_MIN_VERSION=0.7.8
|
||||
MUTTER_MIN_VERSION=2.91.4
|
||||
GTK_MIN_VERSION=2.91.7
|
||||
GIO_MIN_VERSION=2.25.9
|
||||
LIBECAL_REQUIRED=1.6.0
|
||||
LIBEDATASERVER_REQUIRED=1.2.0
|
||||
LIBEDATASERVERUI_REQUIRED=1.2.0
|
||||
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION
|
||||
@ -113,6 +117,10 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
|
||||
AC_SUBST([HAVE_BLUETOOTH],[0])
|
||||
AC_MSG_RESULT([no])])
|
||||
|
||||
PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-1.2 >= $LIBEDATASERVERUI_REQUIRED)
|
||||
AC_SUBST(LIBECAL_CFLAGS)
|
||||
AC_SUBST(LIBECAL_LIBS)
|
||||
|
||||
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
|
||||
# FIXME: metacity-plugins.pc should point directly to its .gir file
|
||||
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`
|
||||
|
@ -25,6 +25,8 @@ dist_images_DATA = \
|
||||
themedir = $(pkgdatadir)/theme
|
||||
dist_theme_DATA = \
|
||||
theme/add-workspace.svg \
|
||||
theme/calendar-arrow-left.svg \
|
||||
theme/calendar-arrow-right.svg \
|
||||
theme/close-window.svg \
|
||||
theme/close.svg \
|
||||
theme/corner-ripple.png \
|
||||
|
82
data/theme/calendar-arrow-left.svg
Normal file
82
data/theme/calendar-arrow-left.svg
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r9942 custom"
|
||||
sodipodi:docname="New document 4">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="8.984481"
|
||||
inkscape:cy="5.6224906"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-width="930"
|
||||
inkscape:window-height="681"
|
||||
inkscape:window-x="1892"
|
||||
inkscape:window-y="272"
|
||||
inkscape:window-maximized="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid17403"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1036.3622)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.43015847;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
id="path18028"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="84.5"
|
||||
sodipodi:cy="337.5"
|
||||
sodipodi:r1="5"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:arg2="1.5707963"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 88.830127,340 80.169873,340 84.5,332.5 z"
|
||||
transform="matrix(0,1.3621708,0.99186247,0,-325.48222,929.32667)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
82
data/theme/calendar-arrow-right.svg
Normal file
82
data/theme/calendar-arrow-right.svg
Normal file
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r9942 custom"
|
||||
sodipodi:docname="arrow-left.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="7.7366092"
|
||||
inkscape:cy="6.4536271"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-width="930"
|
||||
inkscape:window-height="681"
|
||||
inkscape:window-x="1892"
|
||||
inkscape:window-y="272"
|
||||
inkscape:window-maximized="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid17403"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1036.3622)">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.43015847;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
id="path18028"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="84.5"
|
||||
sodipodi:cy="337.5"
|
||||
sodipodi:r1="5"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:arg2="1.5707963"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 88.830127,340 80.169873,340 84.5,332.5 z"
|
||||
transform="matrix(0,1.3621708,-0.99186247,0,342.48324,929.32667)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
@ -674,6 +674,17 @@ StTooltip StLabel {
|
||||
|
||||
/* Calendar popup */
|
||||
|
||||
#calendarArea {
|
||||
/* this is the width of the entire popup */
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
.calendar-vertical-separator {
|
||||
-stipple-width: 1px;
|
||||
-stipple-color: #505050;
|
||||
width: 1.5em;
|
||||
}
|
||||
|
||||
#calendarPopup {
|
||||
border-radius: 5px;
|
||||
background: rgba(0,0,0,0.9);
|
||||
@ -686,37 +697,155 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.calendar {
|
||||
spacing-rows: 5px;
|
||||
spacing-columns: 3px;
|
||||
padding: .4em 1.75em;
|
||||
spacing-rows: 0px;
|
||||
spacing-columns: 0px;
|
||||
}
|
||||
|
||||
.calendar-change-month {
|
||||
.calendar-month-label {
|
||||
color: #666666;
|
||||
font-size: 10px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.calendar-change-month:hover {
|
||||
background: #314a6c;
|
||||
border-radius: 5px;
|
||||
.calendar-change-month-back {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url("calendar-arrow-left.svg");
|
||||
border-radius: 4px;
|
||||
}
|
||||
.calendar-change-month-back:hover {
|
||||
background-color: #999999;
|
||||
}
|
||||
.calendar-change-month-back:active {
|
||||
background-color: #aaaaaa;
|
||||
}
|
||||
|
||||
.calendar-change-month:active {
|
||||
background: #213050;
|
||||
border-radius: 5px;
|
||||
.calendar-change-month-forward {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-image: url("calendar-arrow-right.svg");
|
||||
border-radius: 4px;
|
||||
}
|
||||
.calendar-change-month-forward:hover {
|
||||
background-color: #999999;
|
||||
}
|
||||
.calendar-change-month-forward:active {
|
||||
background-color: #aaaaaa;
|
||||
}
|
||||
|
||||
.datemenu-date-label {
|
||||
padding: .4em 1.75em;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.calendar-day-base {
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.calendar-day-base:hover {
|
||||
background: #777777;
|
||||
}
|
||||
|
||||
.calendar-day-base:active {
|
||||
background: #555555;
|
||||
}
|
||||
|
||||
.calendar-day-heading {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.calendar-week-number {
|
||||
color: #666666;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Hack used in lieu of border-collapse - see calendar.js */
|
||||
.calendar-day {
|
||||
padding: 1px 2px;
|
||||
border: 1px solid #333333;
|
||||
color: #cccccc;
|
||||
border-top-width: 0;
|
||||
border-left-width: 0;
|
||||
}
|
||||
.calendar-day-top {
|
||||
border-top-width: 1px;
|
||||
}
|
||||
.calendar-day-left {
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.calendar-work-day {
|
||||
}
|
||||
|
||||
.calendar-nonwork-day {
|
||||
background-color: rgba(128, 128, 128, .1);
|
||||
}
|
||||
|
||||
.calendar-today {
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
background: #ffffff;
|
||||
color: black;
|
||||
border-radius: 5px;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: #3c3c3c;
|
||||
background-gradient-end: #131313;
|
||||
}
|
||||
|
||||
.calendar-other-month-day {
|
||||
color: #cccccc;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.calendar-day-with-events {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.events-header-vbox {
|
||||
spacing: 10px;
|
||||
}
|
||||
|
||||
.events-header {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.events-header-hbox {
|
||||
spacing: 8px;
|
||||
padding: 0.3em;
|
||||
}
|
||||
|
||||
.events-day-header {
|
||||
font-size: 14px;
|
||||
color: rgba(153, 153, 153, 1.0);
|
||||
}
|
||||
|
||||
.events-day-dayname {
|
||||
font-size: 12px;
|
||||
color: rgba(153, 153, 153, 1.0);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.events-day-time {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.events-day-task {
|
||||
font-size: 12px;
|
||||
color: rgba(153, 153, 153, 1.0);
|
||||
}
|
||||
|
||||
.events-day-name-box {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.events-time-box {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.events-event-box {
|
||||
}
|
||||
|
||||
.url-highlighter {
|
||||
@ -895,10 +1024,6 @@ StTooltip StLabel {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.calendar-calendarweek {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
/* App Switcher */
|
||||
#altTabPopup {
|
||||
padding: 8px;
|
||||
|
@ -19,6 +19,7 @@ nobase_dist_js_DATA = \
|
||||
ui/chrome.js \
|
||||
ui/ctrlAltTab.js \
|
||||
ui/dash.js \
|
||||
ui/dateMenu.js \
|
||||
ui/dnd.js \
|
||||
ui/docDisplay.js \
|
||||
ui/endSessionDialog.js \
|
||||
|
@ -4,19 +4,78 @@ const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
|
||||
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||
|
||||
// in org.gnome.desktop.interface
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
function _sameDay(dateA, dateB) {
|
||||
return (dateA.getDate() == dateB.getDate() &&
|
||||
dateA.getMonth() == dateB.getMonth() &&
|
||||
dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
function _sameYear(dateA, dateB) {
|
||||
return (dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
/* TODO: maybe needs config - right now we assume that Saturday and
|
||||
* Sunday are non-work days (not true in e.g. Israel, it's Sunday and
|
||||
* Monday there)
|
||||
*/
|
||||
function _isWorkDay(date) {
|
||||
return date.getDay() != 0 && date.getDay() != 6;
|
||||
}
|
||||
|
||||
function _getBeginningOfDay(date) {
|
||||
let ret = new Date(date.getTime());
|
||||
ret.setHours(0);
|
||||
ret.setMinutes(0);
|
||||
ret.setSeconds(0);
|
||||
ret.setMilliseconds(0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
function _getEndOfDay(date) {
|
||||
let ret = new Date(date.getTime());
|
||||
ret.setHours(23);
|
||||
ret.setMinutes(59);
|
||||
ret.setSeconds(59);
|
||||
ret.setMilliseconds(999);
|
||||
return ret;
|
||||
}
|
||||
|
||||
function _formatEventTime(event, clockFormat) {
|
||||
let ret;
|
||||
if (event.allDay) {
|
||||
/* Translators: Shown in calendar event list for all day events */
|
||||
ret = _("All Day");
|
||||
} else {
|
||||
switch (clockFormat) {
|
||||
case '24h':
|
||||
ret = event.date.toLocaleFormat('%H:%M');
|
||||
break;
|
||||
|
||||
default:
|
||||
/* explicit fall-through */
|
||||
case '12h':
|
||||
ret = event.date.toLocaleFormat('%l:%M %p');
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function _getCalendarWeekForDate(date) {
|
||||
// Based on the algorithms found here:
|
||||
// http://en.wikipedia.org/wiki/Talk:ISO_week_date
|
||||
@ -43,12 +102,259 @@ function _getDigitWidth(actor){
|
||||
return width;
|
||||
}
|
||||
|
||||
function Calendar() {
|
||||
function _getCalendarDayAbbreviation(dayNumber) {
|
||||
let abbreviations = [
|
||||
/* Translators: Calendar grid abbreviation for Sunday.
|
||||
*
|
||||
* NOTE: These abbreviations are always shown together and in
|
||||
* order, e.g. "S M T W T F S".
|
||||
*/
|
||||
_("S"),
|
||||
/* Translators: Calendar grid abbreviation for Monday */
|
||||
_("M"),
|
||||
/* Translators: Calendar grid abbreviation for Tuesday */
|
||||
_("T"),
|
||||
/* Translators: Calendar grid abbreviation for Wednesday */
|
||||
_("W"),
|
||||
/* Translators: Calendar grid abbreviation for Thursday */
|
||||
_("T"),
|
||||
/* Translators: Calendar grid abbreviation for Friday */
|
||||
_("F"),
|
||||
/* Translators: Calendar grid abbreviation for Saturday */
|
||||
_("S")
|
||||
];
|
||||
return abbreviations[dayNumber];
|
||||
}
|
||||
|
||||
function _getEventDayAbbreviation(dayNumber) {
|
||||
let abbreviations = [
|
||||
/* Translators: Event list abbreviation for Sunday.
|
||||
*
|
||||
* NOTE: These abbreviations are normally not shown together
|
||||
* so they need to be unique (e.g. Tuesday and Thursday cannot
|
||||
* both be 'T').
|
||||
*/
|
||||
_("Su"),
|
||||
/* Translators: Event list abbreviation for Monday */
|
||||
_("M"),
|
||||
/* Translators: Event list abbreviation for Tuesday */
|
||||
_("T"),
|
||||
/* Translators: Event list abbreviation for Wednesday */
|
||||
_("W"),
|
||||
/* Translators: Event list abbreviation for Thursday */
|
||||
_("Th"),
|
||||
/* Translators: Event list abbreviation for Friday */
|
||||
_("F"),
|
||||
/* Translators: Event list abbreviation for Saturday */
|
||||
_("S")
|
||||
];
|
||||
return abbreviations[dayNumber];
|
||||
}
|
||||
|
||||
// Abstraction for an appointment/event in a calendar
|
||||
|
||||
function CalendarEvent(date, summary, allDay) {
|
||||
this._init(date, summary, allDay);
|
||||
}
|
||||
|
||||
CalendarEvent.prototype = {
|
||||
_init: function(date, summary, allDay) {
|
||||
this.date = date;
|
||||
this.summary = summary;
|
||||
this.allDay = allDay;
|
||||
}
|
||||
};
|
||||
|
||||
// Interface for appointments/events - e.g. the contents of a calendar
|
||||
//
|
||||
|
||||
// First, an implementation with no events
|
||||
function EmptyEventSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Calendar.prototype = {
|
||||
EmptyEventSource.prototype = {
|
||||
_init: function() {
|
||||
},
|
||||
|
||||
requestRange: function(begin, end) {
|
||||
},
|
||||
|
||||
getEvents: function(begin, end) {
|
||||
let result = [];
|
||||
return result;
|
||||
},
|
||||
|
||||
hasEvents: function(day) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(EmptyEventSource.prototype);
|
||||
|
||||
// Second, wrap native Evolution event source
|
||||
function EvolutionEventSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
EvolutionEventSource.prototype = {
|
||||
_init: function() {
|
||||
this._native = new Shell.EvolutionEventSource();
|
||||
this._native.connect('changed', Lang.bind(this, function() {
|
||||
this.emit('changed');
|
||||
}));
|
||||
},
|
||||
|
||||
requestRange: function(begin, end) {
|
||||
this._native.request_range(begin.getTime(), end.getTime());
|
||||
},
|
||||
|
||||
getEvents: function(begin, end) {
|
||||
let result = [];
|
||||
let nativeEvents = this._native.get_events(begin.getTime(), end.getTime());
|
||||
for (let n = 0; n < nativeEvents.length; n++) {
|
||||
let nativeEvent = nativeEvents[n];
|
||||
result.push(new CalendarEvent(new Date(nativeEvent.msec_begin), nativeEvent.summary, nativeEvent.all_day));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
hasEvents: function(day) {
|
||||
let dayBegin = _getBeginningOfDay(day);
|
||||
let dayEnd = _getEndOfDay(day);
|
||||
|
||||
let events = this.getEvents(dayBegin, dayEnd);
|
||||
|
||||
if (events.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(EvolutionEventSource.prototype);
|
||||
|
||||
// Finally, an implementation with fake events
|
||||
function FakeEventSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
FakeEventSource.prototype = {
|
||||
_init: function() {
|
||||
|
||||
this._fakeEvents = [];
|
||||
|
||||
// Generate fake events
|
||||
//
|
||||
let midnightToday = _getBeginningOfDay(new Date());
|
||||
let summary = '';
|
||||
|
||||
// '10-oclock pow-wow' is an event occuring IN THE PAST every four days at 10am
|
||||
for (let n = 0; n < 10; n++) {
|
||||
let t = new Date(midnightToday.getTime() - n * 4 * 86400 * 1000);
|
||||
t.setHours(10);
|
||||
summary = '10-oclock pow-wow (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, false));
|
||||
}
|
||||
|
||||
// '11-oclock thing' is an event occuring every three days at 11am
|
||||
for (let n = 0; n < 10; n++) {
|
||||
let t = new Date(midnightToday.getTime() + n * 3 * 86400 * 1000);
|
||||
t.setHours(11);
|
||||
summary = '11-oclock thing (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, false));
|
||||
}
|
||||
|
||||
// 'Weekly Meeting' is an event occuring every seven days at 1:45pm (two days displaced)
|
||||
for (let n = 0; n < 5; n++) {
|
||||
let t = new Date(midnightToday.getTime() + (n * 7 + 2) * 86400 * 1000);
|
||||
t.setHours(13);
|
||||
t.setMinutes(45);
|
||||
summary = 'Weekly Meeting (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, false));
|
||||
}
|
||||
|
||||
// 'Fun All Day' is an all-day event occuring every fortnight (three days displayed)
|
||||
for (let n = 0; n < 10; n++) {
|
||||
let t = new Date(midnightToday.getTime() + (n * 14 + 3) * 86400 * 1000);
|
||||
summary = 'Fun All Day (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, true));
|
||||
}
|
||||
|
||||
// 'Get Married' is an event that actually reflects reality (Dec 4, 2010) :-)
|
||||
this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 4, 16, 0), 'Get Married', false));
|
||||
|
||||
// ditto for 'NE Patriots vs NY Jets'
|
||||
this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 6, 20, 30), 'NE Patriots vs NY Jets', false));
|
||||
|
||||
// An event for tomorrow @6:30pm that is added/removed every five
|
||||
// seconds (to check that the ::changed signal works)
|
||||
let transientEventDate = new Date(midnightToday.getTime() + 86400 * 1000);
|
||||
transientEventDate.setHours(18);
|
||||
transientEventDate.setMinutes(30);
|
||||
transientEventDate.setSeconds(0);
|
||||
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
|
||||
this._includeTransientEvent = false;
|
||||
this._transientEvent = new CalendarEvent(transientEventDate, 'A Transient Event', false);
|
||||
this._transientEventCounter = 1;
|
||||
},
|
||||
|
||||
_updateTransientEvent: function() {
|
||||
this._includeTransientEvent = !this._includeTransientEvent;
|
||||
this._transientEventCounter = this._transientEventCounter + 1;
|
||||
this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
|
||||
this.emit('changed');
|
||||
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
|
||||
},
|
||||
|
||||
requestRange: function(begin, end) {
|
||||
},
|
||||
|
||||
getEvents: function(begin, end) {
|
||||
let result = [];
|
||||
//log('begin:' + begin);
|
||||
//log('end: ' + end);
|
||||
for(let n = 0; n < this._fakeEvents.length; n++) {
|
||||
let event = this._fakeEvents[n];
|
||||
if (event.date >= begin && event.date <= end) {
|
||||
result.push(event);
|
||||
}
|
||||
//log('when:' + event.date + ' summary:' + event.summary);
|
||||
}
|
||||
if (this._includeTransientEvent && this._transientEvent.date >= begin && this._transientEvent.date <= end)
|
||||
result.push(this._transientEvent);
|
||||
result.sort(function(event1, event2) {
|
||||
return event1.date.getTime() - event2.date.getTime();
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
hasEvents: function(day) {
|
||||
let dayBegin = _getBeginningOfDay(day);
|
||||
let dayEnd = _getEndOfDay(day);
|
||||
|
||||
let events = this.getEvents(dayBegin, dayEnd);
|
||||
|
||||
if (events.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
Signals.addSignalMethods(FakeEventSource.prototype);
|
||||
|
||||
// Calendar:
|
||||
// @eventSource: is an object implementing the EventSource API, e.g. the
|
||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
||||
function Calendar(eventSource) {
|
||||
this._init(eventSource);
|
||||
}
|
||||
|
||||
Calendar.prototype = {
|
||||
_init: function(eventSource) {
|
||||
this._eventSource = eventSource;
|
||||
|
||||
this._eventSource.connect('changed', Lang.bind(this, this._update));
|
||||
|
||||
// FIXME: This is actually the fallback method for GTK+ for the week start;
|
||||
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
|
||||
// should add a C function so we can do the full handling.
|
||||
@ -71,6 +377,7 @@ Calendar.prototype = {
|
||||
}
|
||||
|
||||
// Find the ordering for month/year in the calendar heading
|
||||
this._headerFormatWithoutYear = '%B';
|
||||
switch (Gettext_gtk30.gettext('calendar:MY')) {
|
||||
case 'calendar:MY':
|
||||
this._headerFormat = '%B %Y';
|
||||
@ -85,7 +392,7 @@ Calendar.prototype = {
|
||||
}
|
||||
|
||||
// Start off with the current date
|
||||
this.date = new Date();
|
||||
this._selectedDate = new Date();
|
||||
|
||||
this.actor = new St.Table({ homogeneous: false,
|
||||
style_class: 'calendar',
|
||||
@ -100,9 +407,10 @@ Calendar.prototype = {
|
||||
|
||||
// Sets the calendar to show a specific date
|
||||
setDate: function(date) {
|
||||
if (!_sameDay(date, this.date)) {
|
||||
this.date = date;
|
||||
if (!_sameDay(date, this._selectedDate)) {
|
||||
this._selectedDate = date;
|
||||
this._update();
|
||||
this.emit('selected-date-changed', new Date(this._selectedDate));
|
||||
}
|
||||
},
|
||||
|
||||
@ -116,45 +424,36 @@ Calendar.prototype = {
|
||||
{ row: 0, col: 0, col_span: offsetCols + 7 });
|
||||
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange));
|
||||
let [backlabel, forwardlabel] = ['<', '>'];
|
||||
if (St.Widget.get_default_direction () == St.TextDirection.RTL) {
|
||||
[backlabel, forwardlabel] = [forwardlabel, backlabel];
|
||||
}
|
||||
|
||||
let back = new St.Button({ label: backlabel, style_class: 'calendar-change-month' });
|
||||
let back = new St.Button({ style_class: 'calendar-change-month-back' });
|
||||
this._topBox.add(back);
|
||||
back.connect('clicked', Lang.bind(this, this._prevMonth));
|
||||
back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
|
||||
|
||||
this._dateLabel = new St.Label();
|
||||
this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
|
||||
this._monthLabel = new St.Label({style_class: 'calendar-month-label'});
|
||||
this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
|
||||
|
||||
let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' });
|
||||
let forward = new St.Button({ style_class: 'calendar-change-month-forward' });
|
||||
this._topBox.add(forward);
|
||||
forward.connect('clicked', Lang.bind(this, this._nextMonth));
|
||||
forward.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
|
||||
|
||||
// Add weekday labels...
|
||||
//
|
||||
// We need to figure out the abbreviated localized names for the days of the week;
|
||||
// we do this by just getting the next 7 days starting from right now and then putting
|
||||
// them in the right cell in the table. It doesn't matter if we add them in order
|
||||
let iter = new Date(this.date);
|
||||
let iter = new Date(this._selectedDate);
|
||||
iter.setSeconds(0); // Leap second protection. Hah!
|
||||
iter.setHours(12);
|
||||
|
||||
if (this._useWeekdate) {
|
||||
this._weekdateHeader = new St.Label();
|
||||
this.actor.add(this._weekdateHeader,
|
||||
{ row: 1,
|
||||
col: 0,
|
||||
x_fill: false, x_align: St.Align.MIDDLE });
|
||||
this._setWeekdateHeaderWidth();
|
||||
} else {
|
||||
this._weekdateHeader = null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < 7; i++) {
|
||||
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }),
|
||||
// Could use iter.toLocaleFormat('%a') but that normally gives three characters
|
||||
// and we want, ideally, a single character for e.g. S M T W T F S
|
||||
let customDayAbbrev = _getCalendarDayAbbreviation(iter.getDay());
|
||||
let label = new St.Label({ style_class: 'calendar-day-base calendar-day-heading',
|
||||
text: customDayAbbrev });
|
||||
this.actor.add(label,
|
||||
{ row: 1,
|
||||
col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
|
||||
x_fill: false, x_align: St.Align.END });
|
||||
x_fill: false, x_align: St.Align.MIDDLE });
|
||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||
}
|
||||
|
||||
@ -178,33 +477,35 @@ Calendar.prototype = {
|
||||
switch (event.get_scroll_direction()) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
case Clutter.ScrollDirection.LEFT:
|
||||
this._prevMonth();
|
||||
this._onPrevMonthButtonClicked();
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
case Clutter.ScrollDirection.RIGHT:
|
||||
this._nextMonth();
|
||||
this._onNextMonthButtonClicked();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_prevMonth: function() {
|
||||
if (this.date.getMonth() == 0) {
|
||||
this.date.setMonth(11);
|
||||
this.date.setFullYear(this.date.getFullYear() - 1);
|
||||
_onPrevMonthButtonClicked: function() {
|
||||
let newDate = new Date(this._selectedDate);
|
||||
if (newDate.getMonth() == 0) {
|
||||
newDate.setMonth(11);
|
||||
newDate.setFullYear(newDate.getFullYear() - 1);
|
||||
} else {
|
||||
this.date.setMonth(this.date.getMonth() - 1);
|
||||
newDate.setMonth(newDate.getMonth() - 1);
|
||||
}
|
||||
this._update();
|
||||
this.setDate(newDate);
|
||||
},
|
||||
|
||||
_nextMonth: function() {
|
||||
if (this.date.getMonth() == 11) {
|
||||
this.date.setMonth(0);
|
||||
this.date.setFullYear(this.date.getFullYear() + 1);
|
||||
_onNextMonthButtonClicked: function() {
|
||||
let newDate = new Date(this._selectedDate);
|
||||
if (newDate.getMonth() == 11) {
|
||||
newDate.setMonth(0);
|
||||
newDate.setFullYear(newDate.getFullYear() + 1);
|
||||
} else {
|
||||
this.date.setMonth(this.date.getMonth() + 1);
|
||||
newDate.setMonth(newDate.getMonth() + 1);
|
||||
}
|
||||
this._update();
|
||||
this.setDate(newDate);
|
||||
},
|
||||
|
||||
_onSettingsChange: function() {
|
||||
@ -214,7 +515,12 @@ Calendar.prototype = {
|
||||
},
|
||||
|
||||
_update: function() {
|
||||
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
|
||||
let now = new Date();
|
||||
|
||||
if (_sameYear(this._selectedDate, now))
|
||||
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
|
||||
else
|
||||
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
|
||||
|
||||
// Remove everything but the topBox and the weekday labels
|
||||
let children = this.actor.get_children();
|
||||
@ -222,45 +528,201 @@ Calendar.prototype = {
|
||||
children[i].destroy();
|
||||
|
||||
// Start at the beginning of the week before the start of the month
|
||||
let iter = new Date(this.date);
|
||||
iter.setDate(1);
|
||||
iter.setSeconds(0);
|
||||
iter.setHours(12);
|
||||
let daysToWeekStart = (7 + iter.getDay() - this._weekStart) % 7;
|
||||
iter.setTime(iter.getTime() - daysToWeekStart * MSECS_IN_DAY);
|
||||
|
||||
let now = new Date();
|
||||
let beginDate = new Date(this._selectedDate);
|
||||
beginDate.setDate(1);
|
||||
beginDate.setSeconds(0);
|
||||
beginDate.setHours(12);
|
||||
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
|
||||
beginDate.setTime(beginDate.getTime() - daysToWeekStart * MSECS_IN_DAY);
|
||||
|
||||
let iter = new Date(beginDate);
|
||||
let row = 2;
|
||||
while (true) {
|
||||
let label = new St.Label({ text: iter.getDate().toString() });
|
||||
if (_sameDay(now, iter))
|
||||
label.style_class = 'calendar-day calendar-today';
|
||||
else if (iter.getMonth() != this.date.getMonth())
|
||||
label.style_class = 'calendar-day calendar-other-month-day';
|
||||
let button = new St.Button({ label: iter.getDate().toString() });
|
||||
|
||||
let iterStr = iter.toUTCString();
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
let newlySelectedDate = new Date(iterStr);
|
||||
this.setDate(newlySelectedDate);
|
||||
}));
|
||||
|
||||
let hasEvents = this._eventSource.hasEvents(iter);
|
||||
let styleClass = 'calendar-day-base calendar-day';
|
||||
if (_isWorkDay(iter))
|
||||
styleClass += ' calendar-work-day'
|
||||
else
|
||||
label.style_class = 'calendar-day';
|
||||
styleClass += ' calendar-nonwork-day'
|
||||
|
||||
// Hack used in lieu of border-collapse - see gnome-shell.css
|
||||
if (row == 2)
|
||||
styleClass = 'calendar-day-top ' + styleClass;
|
||||
if (iter.getDay() == 0)
|
||||
styleClass = 'calendar-day-left ' + styleClass;
|
||||
|
||||
if (_sameDay(now, iter))
|
||||
styleClass += ' calendar-today';
|
||||
else if (iter.getMonth() != this._selectedDate.getMonth())
|
||||
styleClass += ' calendar-other-month-day';
|
||||
|
||||
if (_sameDay(this._selectedDate, iter))
|
||||
button.add_style_pseudo_class('active');
|
||||
|
||||
if (hasEvents)
|
||||
styleClass += ' calendar-day-with-events'
|
||||
|
||||
button.style_class = styleClass;
|
||||
|
||||
let offsetCols = this._useWeekdate ? 1 : 0;
|
||||
this.actor.add(label,
|
||||
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
|
||||
x_fill: false, x_align: St.Align.END });
|
||||
this.actor.add(button,
|
||||
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
|
||||
|
||||
if (this._useWeekdate && iter.getDay() == 4) {
|
||||
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
|
||||
style_class: 'calendar-day calendar-calendarweek'});
|
||||
style_class: 'calendar-day-base calendar-week-number'});
|
||||
this.actor.add(label,
|
||||
{ row: row, col: 0,
|
||||
x_fill: false, x_align: St.Align.MIDDLE });
|
||||
{ row: row, col: 0, y_align: St.Align.MIDDLE });
|
||||
}
|
||||
|
||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||
if (iter.getDay() == this._weekStart) {
|
||||
// We stop on the first "first day of the week" after the month we are displaying
|
||||
if (iter.getMonth() > this.date.getMonth() || iter.getYear() > this.date.getYear())
|
||||
if (iter.getMonth() > this._selectedDate.getMonth() || iter.getYear() > this._selectedDate.getYear())
|
||||
break;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
// Signal to the event source that we are interested in events
|
||||
// only from this date range
|
||||
this._eventSource.requestRange(beginDate, iter);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Calendar.prototype);
|
||||
|
||||
function EventsList(eventSource) {
|
||||
this._init(eventSource);
|
||||
}
|
||||
|
||||
EventsList.prototype = {
|
||||
_init: function(eventSource) {
|
||||
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
||||
this._date = new Date();
|
||||
this._eventSource = eventSource;
|
||||
this._eventSource.connect('changed', Lang.bind(this, this._update));
|
||||
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
|
||||
this._update();
|
||||
},
|
||||
|
||||
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
|
||||
if (includeDayName) {
|
||||
dayNameBox.add(new St.Label( { style_class: 'events-day-dayname',
|
||||
text: day } ),
|
||||
{ x_fill: true } );
|
||||
}
|
||||
timeBox.add(new St.Label( { style_class: 'events-day-time',
|
||||
text: time} ),
|
||||
{ x_fill: true } );
|
||||
eventTitleBox.add(new St.Label( { style_class: 'events-day-task',
|
||||
text: desc} ));
|
||||
},
|
||||
|
||||
_addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
|
||||
let events = this._eventSource.getEvents(begin, end);
|
||||
|
||||
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
|
||||
|
||||
if (events.length == 0 && !showNothingScheduled)
|
||||
return;
|
||||
|
||||
let vbox = new St.BoxLayout( {vertical: true} );
|
||||
this.actor.add(vbox);
|
||||
|
||||
vbox.add(new St.Label({ style_class: 'events-day-header', text: header }));
|
||||
let box = new St.BoxLayout({style_class: 'events-header-hbox'});
|
||||
let dayNameBox = new St.BoxLayout({ vertical: true, style_class: 'events-day-name-box' });
|
||||
let timeBox = new St.BoxLayout({ vertical: true, style_class: 'events-time-box' });
|
||||
let eventTitleBox = new St.BoxLayout({ vertical: true, style_class: 'events-event-box' });
|
||||
box.add(dayNameBox, {x_fill: false});
|
||||
box.add(timeBox, {x_fill: false});
|
||||
box.add(eventTitleBox, {expand: true});
|
||||
vbox.add(box);
|
||||
|
||||
for (let n = 0; n < events.length; n++) {
|
||||
let event = events[n];
|
||||
let dayString = _getEventDayAbbreviation(event.date.getDay());
|
||||
let timeString = _formatEventTime(event, clockFormat);
|
||||
let summaryString = event.summary;
|
||||
this._addEvent(dayNameBox, timeBox, eventTitleBox, includeDayName, dayString, timeString, summaryString);
|
||||
}
|
||||
|
||||
if (events.length == 0 && showNothingScheduled) {
|
||||
let now = new Date();
|
||||
/* Translators: Text to show if there are no events */
|
||||
let nothingEvent = new CalendarEvent(now, _("Nothing Scheduled"), true);
|
||||
let timeString = _formatEventTime(nothingEvent, clockFormat);
|
||||
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
|
||||
}
|
||||
},
|
||||
|
||||
_showOtherDay: function(day) {
|
||||
this.actor.destroy_children();
|
||||
|
||||
let dayBegin = _getBeginningOfDay(day);
|
||||
let dayEnd = _getEndOfDay(day);
|
||||
|
||||
let dayString;
|
||||
let now = new Date();
|
||||
if (_sameYear(day, now))
|
||||
dayString = day.toLocaleFormat('%A, %B %d');
|
||||
else
|
||||
dayString = day.toLocaleFormat('%A, %B %d, %Y');
|
||||
this._addPeriod(dayString, dayBegin, dayEnd, false, true);
|
||||
},
|
||||
|
||||
_showToday: function() {
|
||||
this.actor.destroy_children();
|
||||
|
||||
let now = new Date();
|
||||
let dayBegin = _getBeginningOfDay(now);
|
||||
let dayEnd = _getEndOfDay(now);
|
||||
this._addPeriod(_("Today"), dayBegin, dayEnd, false, true);
|
||||
|
||||
let tomorrowBegin = new Date(dayBegin.getTime() + 86400 * 1000);
|
||||
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
|
||||
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
|
||||
|
||||
if (dayEnd.getDay() <= 4) {
|
||||
/* if now is Sunday through Thursday show "This week" and include events up until
|
||||
* and including Saturday
|
||||
*/
|
||||
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
|
||||
let thisWeekEnd = new Date(dayEnd.getTime() + (6 - dayEnd.getDay()) * 86400 * 1000);
|
||||
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
|
||||
} else {
|
||||
/* otherwise it's a Friday or Saturday... show "Next week" and include events up
|
||||
* until and including *next* Saturday
|
||||
*/
|
||||
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
|
||||
let nextWeekEnd = new Date(dayEnd.getTime() + (13 - dayEnd.getDay()) * 86400 * 1000);
|
||||
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
|
||||
}
|
||||
},
|
||||
|
||||
// Sets the event list to show events from a specific date
|
||||
setDate: function(date) {
|
||||
if (!_sameDay(date, this._date)) {
|
||||
this._date = date;
|
||||
this._update();
|
||||
}
|
||||
},
|
||||
|
||||
_update: function() {
|
||||
let today = new Date();
|
||||
if (_sameDay (this._date, today)) {
|
||||
this._showToday();
|
||||
} else {
|
||||
this._showOtherDay(this._date);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
212
js/ui/dateMenu.js
Normal file
212
js/ui/dateMenu.js
Normal file
@ -0,0 +1,212 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Cairo = imports.cairo;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Util = imports.misc.util;
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Calendar = imports.ui.calendar;
|
||||
|
||||
// in org.gnome.desktop.interface
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
// in org.gnome.shell.clock
|
||||
const CLOCK_SHOW_DATE_KEY = 'show-date';
|
||||
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
|
||||
|
||||
function _onVertSepRepaint (area)
|
||||
{
|
||||
let cr = area.get_context();
|
||||
let themeNode = area.get_theme_node();
|
||||
let [width, height] = area.get_surface_size();
|
||||
let stippleColor = new Clutter.Color();
|
||||
let stippleWidth = themeNode.get_length('-stipple-width');
|
||||
let x = Math.floor(width/2) + 0.5;
|
||||
themeNode.lookup_color('-stipple-color', false, stippleColor);
|
||||
cr.moveTo(x, 0);
|
||||
cr.lineTo(x, height);
|
||||
Clutter.cairo_set_source_color(cr, stippleColor);
|
||||
cr.setDash([1, 3], 1); // Hard-code for now
|
||||
cr.setLineWidth(stippleWidth);
|
||||
cr.stroke();
|
||||
};
|
||||
|
||||
function DateMenuButton() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
DateMenuButton.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
|
||||
_init: function() {
|
||||
let item;
|
||||
let hbox;
|
||||
let vbox;
|
||||
|
||||
//this._eventSource = new Calendar.EmptyEventSource();
|
||||
//this._eventSource = new Calendar.FakeEventSource();
|
||||
this._eventSource = new Calendar.EvolutionEventSource();
|
||||
|
||||
PanelMenu.Button.prototype._init.call(this, St.Align.START);
|
||||
|
||||
this._clock = new St.Label();
|
||||
this.actor.set_child(this._clock);
|
||||
|
||||
hbox = new St.BoxLayout({name: 'calendarArea'});
|
||||
this.menu.addActor(hbox);
|
||||
|
||||
// Fill up the first column
|
||||
|
||||
vbox = new St.BoxLayout({vertical: true});
|
||||
hbox.add(vbox);
|
||||
|
||||
// Date
|
||||
this._date = new St.Label();
|
||||
this._date.style_class = 'datemenu-date-label';
|
||||
vbox.add(this._date);
|
||||
|
||||
this._eventList = new Calendar.EventsList(this._eventSource);
|
||||
|
||||
// Calendar
|
||||
this._calendar = new Calendar.Calendar(this._eventSource);
|
||||
this._calendar.connect('selected-date-changed',
|
||||
Lang.bind(this, function(calendar, date) {
|
||||
this._eventList.setDate(date);
|
||||
}));
|
||||
vbox.add(this._calendar.actor);
|
||||
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
item.setColumnWidths(1);
|
||||
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
|
||||
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
||||
vbox.add(item.actor);
|
||||
|
||||
// Add vertical separator
|
||||
|
||||
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
||||
pseudo_class: 'highlighted' });
|
||||
item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
|
||||
hbox.add(item);
|
||||
|
||||
// Fill up the second column
|
||||
|
||||
vbox = new St.BoxLayout({vertical: true});
|
||||
hbox.add(vbox);
|
||||
|
||||
// Event list
|
||||
vbox.add(this._eventList.actor);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
||||
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
||||
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
|
||||
// Whenever the menu is opened, select today
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
||||
if (isOpen) {
|
||||
let now = new Date();
|
||||
this._calendar.setDate(now);
|
||||
// No need to update this._eventList as ::selected-date-changed
|
||||
// signal will fire
|
||||
}
|
||||
}));
|
||||
|
||||
// Done with hbox for calendar and event list
|
||||
|
||||
// Track changes to clock settings
|
||||
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
|
||||
this._desktopSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
|
||||
this._clockSettings.connect('changed', Lang.bind(this, this._updateClockAndDate));
|
||||
|
||||
// Start the clock
|
||||
this._updateClockAndDate();
|
||||
},
|
||||
|
||||
_updateClockAndDate: function() {
|
||||
let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
|
||||
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
|
||||
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
|
||||
|
||||
let clockFormat;
|
||||
let dateFormat;
|
||||
|
||||
switch (format) {
|
||||
case '24h':
|
||||
if (showDate)
|
||||
/* Translators: This is the time format with date used
|
||||
in 24-hour mode. */
|
||||
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
|
||||
: _("%a %b %e, %R");
|
||||
else
|
||||
/* Translators: This is the time format without date used
|
||||
in 24-hour mode. */
|
||||
clockFormat = showSeconds ? _("%a %R:%S")
|
||||
: _("%a %R");
|
||||
break;
|
||||
case '12h':
|
||||
default:
|
||||
if (showDate)
|
||||
/* Translators: This is a time format with date used
|
||||
for AM/PM. */
|
||||
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
|
||||
: _("%a %b %e, %l:%M %p");
|
||||
else
|
||||
/* Translators: This is a time format without date used
|
||||
for AM/PM. */
|
||||
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
|
||||
: _("%a %l:%M %p");
|
||||
break;
|
||||
}
|
||||
|
||||
let displayDate = new Date();
|
||||
let msecRemaining;
|
||||
if (showSeconds) {
|
||||
msecRemaining = 1000 - displayDate.getMilliseconds();
|
||||
if (msecRemaining < 50) {
|
||||
displayDate.setSeconds(displayDate.getSeconds() + 1);
|
||||
msecRemaining += 1000;
|
||||
}
|
||||
} else {
|
||||
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
|
||||
displayDate.getMilliseconds());
|
||||
if (msecRemaining < 500) {
|
||||
displayDate.setMinutes(displayDate.getMinutes() + 1);
|
||||
msecRemaining += 60000;
|
||||
}
|
||||
}
|
||||
|
||||
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
|
||||
|
||||
/* Translators: This is the date format to use when the calendar popup is
|
||||
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
|
||||
*/
|
||||
dateFormat = _("%A %B %e, %Y");
|
||||
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
||||
|
||||
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
|
||||
return false;
|
||||
},
|
||||
|
||||
_onPreferencesActivate: function() {
|
||||
this.menu.close();
|
||||
Util.spawnDesktop('gnome-datetime-panel');
|
||||
},
|
||||
|
||||
_onOpenCalendarActivate: function() {
|
||||
this.menu.close();
|
||||
// TODO: pass '-c calendar' (to force the calendar at startup)
|
||||
// TODO: pass the selected day
|
||||
Util.spawnDesktop('evolution');
|
||||
},
|
||||
};
|
@ -284,10 +284,8 @@ function _relayout() {
|
||||
|
||||
// To avoid updating the position and size of the workspaces
|
||||
// in the overview, we just hide the overview. The positions
|
||||
// will be updated when it is next shown. We do the same for
|
||||
// the calendar popdown.
|
||||
// will be updated when it is next shown.
|
||||
overview.hide();
|
||||
panel.hideCalendar();
|
||||
}
|
||||
|
||||
// metacity-clutter currently uses the same prefs as plain metacity,
|
||||
|
126
js/ui/panel.js
126
js/ui/panel.js
@ -17,6 +17,7 @@ const Overview = imports.ui.overview;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const StatusMenu = imports.ui.statusMenu;
|
||||
const DateMenu = imports.ui.dateMenu;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
@ -492,121 +493,6 @@ AppMenuButton.prototype = {
|
||||
|
||||
Signals.addSignalMethods(AppMenuButton.prototype);
|
||||
|
||||
function ClockButton() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
ClockButton.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.Bin({ style_class: 'panel-button',
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
track_hover: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('button-press-event',
|
||||
Lang.bind(this, this._toggleCalendar));
|
||||
|
||||
this._clock = new St.Label();
|
||||
this.actor.set_child(this._clock);
|
||||
|
||||
this._calendarPopup = null;
|
||||
|
||||
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
|
||||
|
||||
this._desktopSettings.connect('changed', Lang.bind(this, this._updateClock));
|
||||
this._clockSettings.connect('changed', Lang.bind(this, this._updateClock));
|
||||
|
||||
// Start the clock
|
||||
this._updateClock();
|
||||
},
|
||||
|
||||
closeCalendar: function() {
|
||||
if (!this._calendarPopup || !this._calendarPopup.isOpen)
|
||||
return;
|
||||
|
||||
this._calendarPopup.hide();
|
||||
|
||||
this.actor.remove_style_pseudo_class('pressed');
|
||||
},
|
||||
|
||||
openCalendar: function() {
|
||||
this._calendarPopup.show();
|
||||
|
||||
this.actor.add_style_pseudo_class('pressed');
|
||||
},
|
||||
|
||||
_toggleCalendar: function() {
|
||||
if (this._calendarPopup == null) {
|
||||
this._calendarPopup = new CalendarPopup();
|
||||
this._calendarPopup.actor.hide();
|
||||
}
|
||||
|
||||
if (!this._calendarPopup.isOpen)
|
||||
this.openCalendar();
|
||||
else
|
||||
this.closeCalendar();
|
||||
},
|
||||
|
||||
_updateClock: function() {
|
||||
let format = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
|
||||
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
|
||||
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
|
||||
|
||||
let clockFormat;
|
||||
switch (format) {
|
||||
case '24h':
|
||||
if (showDate)
|
||||
/* Translators: This is the time format with date used
|
||||
in 24-hour mode. */
|
||||
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
|
||||
: _("%a %b %e, %R");
|
||||
else
|
||||
/* Translators: This is the time format without date used
|
||||
in 24-hour mode. */
|
||||
clockFormat = showSeconds ? _("%a %R:%S")
|
||||
: _("%a %R");
|
||||
break;
|
||||
case '12h':
|
||||
default:
|
||||
if (showDate)
|
||||
/* Translators: This is a time format with date used
|
||||
for AM/PM. */
|
||||
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
|
||||
: _("%a %b %e, %l:%M %p");
|
||||
else
|
||||
/* Translators: This is a time format without date used
|
||||
for AM/PM. */
|
||||
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
|
||||
: _("%a %l:%M %p");
|
||||
break;
|
||||
}
|
||||
|
||||
let displayDate = new Date();
|
||||
let msecRemaining;
|
||||
if (showSeconds) {
|
||||
msecRemaining = 1000 - displayDate.getMilliseconds();
|
||||
if (msecRemaining < 50) {
|
||||
displayDate.setSeconds(displayDate.getSeconds() + 1);
|
||||
msecRemaining += 1000;
|
||||
}
|
||||
} else {
|
||||
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
|
||||
displayDate.getMilliseconds());
|
||||
if (msecRemaining < 500) {
|
||||
displayDate.setMinutes(displayDate.getMinutes() + 1);
|
||||
msecRemaining += 60000;
|
||||
}
|
||||
}
|
||||
|
||||
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
|
||||
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClock));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
function Panel() {
|
||||
this._init();
|
||||
}
|
||||
@ -803,9 +689,9 @@ Panel.prototype = {
|
||||
this._menus.addMenu(appMenuButton.menu);
|
||||
|
||||
/* center */
|
||||
|
||||
this._clockButton = new ClockButton();
|
||||
this._centerBox.add(this._clockButton.actor, { y_fill: true });
|
||||
this._dateMenu = new DateMenu.DateMenuButton();
|
||||
this._centerBox.add(this._dateMenu.actor, { y_fill: true });
|
||||
this._menus.addMenu(this._dateMenu.menu);
|
||||
|
||||
/* right */
|
||||
|
||||
@ -884,10 +770,6 @@ Panel.prototype = {
|
||||
this._rightBox.add(this._statusmenu.actor);
|
||||
},
|
||||
|
||||
hideCalendar: function() {
|
||||
this._clockButton.closeCalendar();
|
||||
},
|
||||
|
||||
startupAnimation: function() {
|
||||
this.actor.y = -this.actor.height;
|
||||
Tweener.addTween(this.actor,
|
||||
|
22
src/Makefile-calendar-client.am
Normal file
22
src/Makefile-calendar-client.am
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
noinst_LTLIBRARIES += libcalendar-client.la
|
||||
|
||||
libcalendar_client_la_SOURCES = \
|
||||
calendar-client/calendar-client.h calendar-client/calendar-client.c \
|
||||
calendar-client/calendar-debug.h \
|
||||
calendar-client/calendar-sources.c calendar-client/calendar-sources.h \
|
||||
$(NULL)
|
||||
|
||||
libcalendar_client_la_CFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-DG_LOG_DOMAIN=\"CalendarClient\" \
|
||||
$(LIBECAL_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
libcalendar_client_la_LIBADD = $(LIBECAL_LIBS)
|
||||
|
||||
EXTRA_DIST += calendar-client/README
|
@ -27,6 +27,7 @@ include Makefile-gdmuser.am
|
||||
include Makefile-st.am
|
||||
include Makefile-tray.am
|
||||
include Makefile-gvc.am
|
||||
include Makefile-calendar-client.am
|
||||
|
||||
gnome_shell_cflags = \
|
||||
$(MUTTER_PLUGIN_CFLAGS) \
|
||||
@ -89,6 +90,8 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-doc-system.c \
|
||||
shell-drawing.c \
|
||||
shell-embedded-window.c \
|
||||
shell-evolution-event-source.h \
|
||||
shell-evolution-event-source.c \
|
||||
shell-generic-container.c \
|
||||
shell-gtk-embed.c \
|
||||
shell-global.c \
|
||||
@ -212,7 +215,9 @@ libgnome_shell_la_LIBADD = \
|
||||
libst-1.0.la \
|
||||
libgdmuser-1.0.la \
|
||||
libtray.la \
|
||||
libgvc.la
|
||||
libgvc.la \
|
||||
libcalendar-client.la \
|
||||
$(NULL)
|
||||
|
||||
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
|
||||
|
||||
|
1
src/calendar-client/README
Normal file
1
src/calendar-client/README
Normal file
@ -0,0 +1 @@
|
||||
Please keep in sync with gnome-panel.
|
2169
src/calendar-client/calendar-client.c
Normal file
2169
src/calendar-client/calendar-client.c
Normal file
File diff suppressed because it is too large
Load Diff
149
src/calendar-client/calendar-client.h
Normal file
149
src/calendar-client/calendar-client.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* Mark McLoughlin <mark@skynet.ie>
|
||||
* William Jon McCann <mccann@jhu.edu>
|
||||
* Martin Grimme <martin@pycage.de>
|
||||
* Christian Kellner <gicmo@xatom.net>
|
||||
*/
|
||||
|
||||
#ifndef __CALENDAR_CLIENT_H__
|
||||
#define __CALENDAR_CLIENT_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CALENDAR_EVENT_APPOINTMENT = 1 << 0,
|
||||
CALENDAR_EVENT_TASK = 1 << 1,
|
||||
CALENDAR_EVENT_ALL = (1 << 2) - 1
|
||||
} CalendarEventType;
|
||||
|
||||
#define CALENDAR_TYPE_CLIENT (calendar_client_get_type ())
|
||||
#define CALENDAR_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_CLIENT, CalendarClient))
|
||||
#define CALENDAR_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_CLIENT, CalendarClientClass))
|
||||
#define CALENDAR_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_CLIENT))
|
||||
#define CALENDAR_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_CLIENT))
|
||||
#define CALENDAR_CLIENT_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_CLIENT, CalendarClientClass))
|
||||
|
||||
typedef struct _CalendarClient CalendarClient;
|
||||
typedef struct _CalendarClientClass CalendarClientClass;
|
||||
typedef struct _CalendarClientPrivate CalendarClientPrivate;
|
||||
|
||||
struct _CalendarClient
|
||||
{
|
||||
GObject parent;
|
||||
CalendarClientPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CalendarClientClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* appointments_changed) (CalendarClient *client);
|
||||
void (* tasks_changed) (CalendarClient *client);
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
time_t start_time;
|
||||
time_t end_time;
|
||||
} CalendarOccurrence;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *uid;
|
||||
char *rid;
|
||||
char *uri;
|
||||
char *summary;
|
||||
char *description;
|
||||
char *color_string;
|
||||
time_t start_time;
|
||||
time_t end_time;
|
||||
guint is_all_day : 1;
|
||||
|
||||
/* Only used internally */
|
||||
GSList *occurrences;
|
||||
} CalendarAppointment;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *uid;
|
||||
char *summary;
|
||||
char *description;
|
||||
char *color_string;
|
||||
char *url;
|
||||
time_t start_time;
|
||||
time_t due_time;
|
||||
guint percent_complete;
|
||||
time_t completed_time;
|
||||
int priority;
|
||||
} CalendarTask;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
CalendarAppointment appointment;
|
||||
CalendarTask task;
|
||||
} event;
|
||||
CalendarEventType type;
|
||||
} CalendarEvent;
|
||||
|
||||
#define CALENDAR_EVENT(e) ((CalendarEvent *)(e))
|
||||
#define CALENDAR_APPOINTMENT(e) ((CalendarAppointment *)(e))
|
||||
#define CALENDAR_TASK(e) ((CalendarTask *)(e))
|
||||
|
||||
typedef void (* CalendarDayIter) (CalendarClient *client,
|
||||
guint day,
|
||||
gpointer user_data);
|
||||
|
||||
|
||||
GType calendar_client_get_type (void) G_GNUC_CONST;
|
||||
CalendarClient *calendar_client_new (void);
|
||||
|
||||
void calendar_client_get_date (CalendarClient *client,
|
||||
guint *year,
|
||||
guint *month,
|
||||
guint *day);
|
||||
void calendar_client_select_month (CalendarClient *client,
|
||||
guint month,
|
||||
guint year);
|
||||
void calendar_client_select_day (CalendarClient *client,
|
||||
guint day);
|
||||
|
||||
GSList *calendar_client_get_events (CalendarClient *client,
|
||||
CalendarEventType event_mask);
|
||||
void calendar_client_foreach_appointment_day (CalendarClient *client,
|
||||
CalendarDayIter iter_func,
|
||||
gpointer user_data);
|
||||
|
||||
void calendar_client_set_task_completed (CalendarClient *client,
|
||||
char *task_uid,
|
||||
gboolean task_completed,
|
||||
guint percent_complete);
|
||||
|
||||
void calendar_event_free (CalendarEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CALENDAR_CLIENT_H__ */
|
52
src/calendar-client/calendar-debug.h
Normal file
52
src/calendar-client/calendar-debug.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* Mark McLoughlin <mark@skynet.ie>
|
||||
*/
|
||||
|
||||
#ifndef __CALENDAR_DEBUG_H__
|
||||
#define __CALENDAR_DEBUG_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef CALENDAR_ENABLE_DEBUG
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef G_HAVE_ISO_VARARGS
|
||||
# define dprintf(...) fprintf (stderr, __VA_ARGS__);
|
||||
#elif defined(G_HAVE_GNUC_VARARGS)
|
||||
# define dprintf(args...) fprintf (stderr, args);
|
||||
#endif
|
||||
|
||||
#else /* if !defined (CALENDAR_DEBUG) */
|
||||
|
||||
#ifdef G_HAVE_ISO_VARARGS
|
||||
# define dprintf(...)
|
||||
#elif defined(G_HAVE_GNUC_VARARGS)
|
||||
# define dprintf(args...)
|
||||
#endif
|
||||
|
||||
#endif /* CALENDAR_ENABLE_DEBUG */
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CALENDAR_DEBUG_H__ */
|
658
src/calendar-client/calendar-sources.c
Normal file
658
src/calendar-client/calendar-sources.c
Normal file
@ -0,0 +1,658 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* Mark McLoughlin <mark@skynet.ie>
|
||||
* William Jon McCann <mccann@jhu.edu>
|
||||
* Martin Grimme <martin@pycage.de>
|
||||
* Christian Kellner <gicmo@xatom.net>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "calendar-sources.h"
|
||||
|
||||
#include <libintl.h>
|
||||
#include <string.h>
|
||||
#include <gconf/gconf-client.h>
|
||||
#define HANDLE_LIBICAL_MEMORY
|
||||
#include <libecal/e-cal.h>
|
||||
#include <libedataserver/e-source-list.h>
|
||||
#include <libedataserverui/e-passwords.h>
|
||||
|
||||
#undef CALENDAR_ENABLE_DEBUG
|
||||
#include "calendar-debug.h"
|
||||
|
||||
#ifndef _
|
||||
#define _(x) gettext(x)
|
||||
#endif
|
||||
|
||||
#ifndef N_
|
||||
#define N_(x) x
|
||||
#endif
|
||||
|
||||
#define CALENDAR_SOURCES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesPrivate))
|
||||
|
||||
#define CALENDAR_SOURCES_EVO_DIR "/apps/evolution"
|
||||
#define CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/calendar/sources"
|
||||
#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/display"
|
||||
#define CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR "/selected_calendars"
|
||||
#define CALENDAR_SOURCES_TASK_SOURCES_KEY CALENDAR_SOURCES_EVO_DIR "/tasks/sources"
|
||||
#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR CALENDAR_SOURCES_EVO_DIR "/calendar/tasks"
|
||||
#define CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR "/selected_tasks"
|
||||
|
||||
typedef struct _CalendarSourceData CalendarSourceData;
|
||||
|
||||
struct _CalendarSourceData
|
||||
{
|
||||
ECalSourceType source_type;
|
||||
CalendarSources *sources;
|
||||
guint changed_signal;
|
||||
|
||||
GSList *clients;
|
||||
GSList *selected_sources;
|
||||
ESourceList *esource_list;
|
||||
|
||||
guint selected_sources_listener;
|
||||
char *selected_sources_dir;
|
||||
|
||||
guint timeout_id;
|
||||
|
||||
guint loaded : 1;
|
||||
};
|
||||
|
||||
struct _CalendarSourcesPrivate
|
||||
{
|
||||
CalendarSourceData appointment_sources;
|
||||
CalendarSourceData task_sources;
|
||||
|
||||
GConfClient *gconf_client;
|
||||
};
|
||||
|
||||
static void calendar_sources_class_init (CalendarSourcesClass *klass);
|
||||
static void calendar_sources_init (CalendarSources *sources);
|
||||
static void calendar_sources_finalize (GObject *object);
|
||||
|
||||
static void backend_died_cb (ECal *client, CalendarSourceData *source_data);
|
||||
static void calendar_sources_esource_list_changed (ESourceList *source_list,
|
||||
CalendarSourceData *source_data);
|
||||
|
||||
enum
|
||||
{
|
||||
APPOINTMENT_SOURCES_CHANGED,
|
||||
TASK_SOURCES_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals [LAST_SIGNAL] = { 0, };
|
||||
|
||||
static GObjectClass *parent_class = NULL;
|
||||
static CalendarSources *calendar_sources_singleton = NULL;
|
||||
|
||||
GType
|
||||
calendar_sources_get_type (void)
|
||||
{
|
||||
static GType sources_type = 0;
|
||||
|
||||
if (!sources_type)
|
||||
{
|
||||
static const GTypeInfo sources_info =
|
||||
{
|
||||
sizeof (CalendarSourcesClass),
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
(GClassInitFunc) calendar_sources_class_init,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
sizeof (CalendarSources),
|
||||
0, /* n_preallocs */
|
||||
(GInstanceInitFunc) calendar_sources_init,
|
||||
};
|
||||
|
||||
sources_type = g_type_register_static (G_TYPE_OBJECT,
|
||||
"CalendarSources",
|
||||
&sources_info, 0);
|
||||
}
|
||||
|
||||
return sources_type;
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_class_init (CalendarSourcesClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
gobject_class->finalize = calendar_sources_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (CalendarSourcesPrivate));
|
||||
|
||||
signals [APPOINTMENT_SOURCES_CHANGED] =
|
||||
g_signal_new ("appointment-sources-changed",
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (CalendarSourcesClass,
|
||||
appointment_sources_changed),
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
signals [TASK_SOURCES_CHANGED] =
|
||||
g_signal_new ("task-sources-changed",
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (CalendarSourcesClass,
|
||||
task_sources_changed),
|
||||
NULL,
|
||||
NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_init (CalendarSources *sources)
|
||||
{
|
||||
sources->priv = CALENDAR_SOURCES_GET_PRIVATE (sources);
|
||||
|
||||
sources->priv->appointment_sources.source_type = E_CAL_SOURCE_TYPE_EVENT;
|
||||
sources->priv->appointment_sources.sources = sources;
|
||||
sources->priv->appointment_sources.changed_signal = signals [APPOINTMENT_SOURCES_CHANGED];
|
||||
sources->priv->appointment_sources.timeout_id = 0;
|
||||
|
||||
sources->priv->task_sources.source_type = E_CAL_SOURCE_TYPE_TODO;
|
||||
sources->priv->task_sources.sources = sources;
|
||||
sources->priv->task_sources.changed_signal = signals [TASK_SOURCES_CHANGED];
|
||||
sources->priv->task_sources.timeout_id = 0;
|
||||
|
||||
sources->priv->gconf_client = gconf_client_get_default ();
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_finalize_source_data (CalendarSources *sources,
|
||||
CalendarSourceData *source_data)
|
||||
{
|
||||
if (source_data->loaded)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (source_data->selected_sources_dir)
|
||||
{
|
||||
gconf_client_remove_dir (sources->priv->gconf_client,
|
||||
source_data->selected_sources_dir,
|
||||
NULL);
|
||||
|
||||
g_free (source_data->selected_sources_dir);
|
||||
source_data->selected_sources_dir = NULL;
|
||||
}
|
||||
|
||||
if (source_data->selected_sources_listener)
|
||||
{
|
||||
gconf_client_notify_remove (sources->priv->gconf_client,
|
||||
source_data->selected_sources_listener);
|
||||
source_data->selected_sources_listener = 0;
|
||||
}
|
||||
|
||||
for (l = source_data->clients; l; l = l->next)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
|
||||
G_CALLBACK (backend_died_cb),
|
||||
source_data);
|
||||
g_object_unref (l->data);
|
||||
}
|
||||
g_slist_free (source_data->clients);
|
||||
source_data->clients = NULL;
|
||||
|
||||
if (source_data->esource_list)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (source_data->esource_list,
|
||||
G_CALLBACK (calendar_sources_esource_list_changed),
|
||||
source_data);
|
||||
g_object_unref (source_data->esource_list);
|
||||
}
|
||||
source_data->esource_list = NULL;
|
||||
|
||||
for (l = source_data->selected_sources; l; l = l->next)
|
||||
g_free (l->data);
|
||||
g_slist_free (source_data->selected_sources);
|
||||
source_data->selected_sources = NULL;
|
||||
|
||||
if (source_data->timeout_id != 0)
|
||||
{
|
||||
g_source_remove (source_data->timeout_id);
|
||||
source_data->timeout_id = 0;
|
||||
}
|
||||
|
||||
source_data->loaded = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_finalize (GObject *object)
|
||||
{
|
||||
CalendarSources *sources = CALENDAR_SOURCES (object);
|
||||
|
||||
calendar_sources_finalize_source_data (sources, &sources->priv->appointment_sources);
|
||||
calendar_sources_finalize_source_data (sources, &sources->priv->task_sources);
|
||||
|
||||
if (sources->priv->gconf_client)
|
||||
g_object_unref (sources->priv->gconf_client);
|
||||
sources->priv->gconf_client = NULL;
|
||||
|
||||
if (G_OBJECT_CLASS (parent_class)->finalize)
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
CalendarSources *
|
||||
calendar_sources_get (void)
|
||||
{
|
||||
gpointer singleton_location = &calendar_sources_singleton;
|
||||
|
||||
if (calendar_sources_singleton)
|
||||
return g_object_ref (calendar_sources_singleton);
|
||||
|
||||
calendar_sources_singleton = g_object_new (CALENDAR_TYPE_SOURCES, NULL);
|
||||
g_object_add_weak_pointer (G_OBJECT (calendar_sources_singleton),
|
||||
singleton_location);
|
||||
|
||||
return calendar_sources_singleton;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_source_selected (ESource *esource,
|
||||
GSList *selected_sources)
|
||||
{
|
||||
const char *uid;
|
||||
GSList *l;
|
||||
|
||||
uid = e_source_peek_uid (esource);
|
||||
|
||||
for (l = selected_sources; l; l = l->next)
|
||||
{
|
||||
const char *source = l->data;
|
||||
|
||||
if (!strcmp (source, uid))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char *
|
||||
auth_func_cb (ECal *ecal,
|
||||
const char *prompt,
|
||||
const char *key,
|
||||
gpointer user_data)
|
||||
{
|
||||
ESource *source;
|
||||
const gchar *auth_domain;
|
||||
const gchar *component_name;
|
||||
|
||||
source = e_cal_get_source (ecal);
|
||||
auth_domain = e_source_get_property (source, "auth-domain");
|
||||
component_name = auth_domain ? auth_domain : "Calendar";
|
||||
|
||||
return e_passwords_get_password (component_name, key);
|
||||
}
|
||||
|
||||
/* The clients are just created here but not loaded */
|
||||
static ECal *
|
||||
get_ecal_from_source (ESource *esource,
|
||||
ECalSourceType source_type,
|
||||
GSList *existing_clients)
|
||||
{
|
||||
ECal *retval;
|
||||
|
||||
if (existing_clients)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
for (l = existing_clients; l; l = l->next)
|
||||
{
|
||||
ECal *client = E_CAL (l->data);
|
||||
|
||||
if (e_source_equal (esource, e_cal_get_source (client)))
|
||||
{
|
||||
dprintf (" load_esource: found existing source ... returning that\n");
|
||||
|
||||
return g_object_ref (client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = e_cal_new (esource, source_type);
|
||||
if (!retval)
|
||||
{
|
||||
g_warning ("Could not load source '%s' from '%s'\n",
|
||||
e_source_peek_name (esource),
|
||||
e_source_peek_relative_uri (esource));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e_cal_set_auth_func (retval, auth_func_cb, NULL);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* - Order doesn't matter
|
||||
* - Can just compare object pointers since we
|
||||
* re-use client connections
|
||||
*/
|
||||
static gboolean
|
||||
compare_ecal_lists (GSList *a,
|
||||
GSList *b)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (g_slist_length (a) != g_slist_length (b))
|
||||
return FALSE;
|
||||
|
||||
for (l = a; l; l = l->next)
|
||||
{
|
||||
if (!g_slist_find (b, l->data))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static inline void
|
||||
debug_dump_selected_sources (GSList *selected_sources)
|
||||
{
|
||||
#ifdef CALENDAR_ENABLE_DEBUG
|
||||
GSList *l;
|
||||
|
||||
dprintf ("Selected sources:\n");
|
||||
for (l = selected_sources; l; l = l->next)
|
||||
{
|
||||
char *source = l->data;
|
||||
|
||||
dprintf (" %s\n", source);
|
||||
}
|
||||
dprintf ("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
debug_dump_ecal_list (GSList *ecal_list)
|
||||
{
|
||||
#ifdef CALENDAR_ENABLE_DEBUG
|
||||
GSList *l;
|
||||
|
||||
dprintf ("Loaded clients:\n");
|
||||
for (l = ecal_list; l; l = l->next)
|
||||
{
|
||||
ECal *client = l->data;
|
||||
ESource *source = e_cal_get_source (client);
|
||||
|
||||
dprintf (" %s %s %s\n",
|
||||
e_source_peek_uid (source),
|
||||
e_source_peek_name (source),
|
||||
e_cal_get_uri (client));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_load_esource_list (CalendarSourceData *source_data);
|
||||
|
||||
static gboolean
|
||||
backend_restart (gpointer data)
|
||||
{
|
||||
CalendarSourceData *source_data = data;
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
|
||||
source_data->timeout_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
backend_died_cb (ECal *client, CalendarSourceData *source_data)
|
||||
{
|
||||
const char *uristr;
|
||||
|
||||
source_data->clients = g_slist_remove (source_data->clients, client);
|
||||
if (g_slist_length (source_data->clients) < 1)
|
||||
{
|
||||
g_slist_free (source_data->clients);
|
||||
source_data->clients = NULL;
|
||||
}
|
||||
uristr = e_cal_get_uri (client);
|
||||
g_warning ("The calendar backend for %s has crashed.", uristr);
|
||||
|
||||
if (source_data->timeout_id != 0)
|
||||
{
|
||||
g_source_remove (source_data->timeout_id);
|
||||
source_data->timeout_id = 0;
|
||||
}
|
||||
|
||||
source_data->timeout_id = g_timeout_add_seconds (2, backend_restart,
|
||||
source_data);
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_load_esource_list (CalendarSourceData *source_data)
|
||||
{
|
||||
GSList *clients = NULL;
|
||||
GSList *groups, *l;
|
||||
gboolean emit_signal = FALSE;
|
||||
|
||||
g_return_if_fail (source_data->esource_list != NULL);
|
||||
|
||||
debug_dump_selected_sources (source_data->selected_sources);
|
||||
|
||||
dprintf ("Source groups:\n");
|
||||
groups = e_source_list_peek_groups (source_data->esource_list);
|
||||
for (l = groups; l; l = l->next)
|
||||
{
|
||||
GSList *esources, *s;
|
||||
|
||||
dprintf (" %s\n", e_source_group_peek_uid (l->data));
|
||||
dprintf (" sources:\n");
|
||||
|
||||
esources = e_source_group_peek_sources (l->data);
|
||||
for (s = esources; s; s = s->next)
|
||||
{
|
||||
ESource *esource = E_SOURCE (s->data);
|
||||
ECal *client;
|
||||
|
||||
dprintf (" type = '%s' uid = '%s', name = '%s', relative uri = '%s': \n",
|
||||
source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task",
|
||||
e_source_peek_uid (esource),
|
||||
e_source_peek_name (esource),
|
||||
e_source_peek_relative_uri (esource));
|
||||
|
||||
if (is_source_selected (esource, source_data->selected_sources) &&
|
||||
(client = get_ecal_from_source (esource, source_data->source_type, source_data->clients)))
|
||||
{
|
||||
clients = g_slist_prepend (clients, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
dprintf ("\n");
|
||||
|
||||
if (source_data->loaded &&
|
||||
!compare_ecal_lists (source_data->clients, clients))
|
||||
emit_signal = TRUE;
|
||||
|
||||
for (l = source_data->clients; l; l = l->next)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
|
||||
G_CALLBACK (backend_died_cb),
|
||||
source_data);
|
||||
|
||||
g_object_unref (l->data);
|
||||
}
|
||||
g_slist_free (source_data->clients);
|
||||
source_data->clients = g_slist_reverse (clients);
|
||||
|
||||
/* connect to backend_died after we disconnected the previous signal
|
||||
* handlers. If we do it before, we'll lose some handlers (for clients that
|
||||
* were already there before) */
|
||||
for (l = source_data->clients; l; l = l->next)
|
||||
{
|
||||
g_signal_connect (G_OBJECT (l->data), "backend_died",
|
||||
G_CALLBACK (backend_died_cb), source_data);
|
||||
}
|
||||
|
||||
if (emit_signal)
|
||||
{
|
||||
dprintf ("Emitting %s-sources-changed signal\n",
|
||||
source_data->source_type == E_CAL_SOURCE_TYPE_EVENT ? "appointment" : "task");
|
||||
g_signal_emit (source_data->sources, source_data->changed_signal, 0);
|
||||
}
|
||||
|
||||
debug_dump_ecal_list (source_data->clients);
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_esource_list_changed (ESourceList *source_list,
|
||||
CalendarSourceData *source_data)
|
||||
|
||||
{
|
||||
dprintf ("ESourceList changed, reloading\n");
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_selected_sources_notify (GConfClient *client,
|
||||
guint cnx_id,
|
||||
GConfEntry *entry,
|
||||
CalendarSourceData *source_data)
|
||||
{
|
||||
GSList *l;
|
||||
|
||||
if (!entry->value ||
|
||||
entry->value->type != GCONF_VALUE_LIST ||
|
||||
gconf_value_get_list_type (entry->value) != GCONF_VALUE_STRING)
|
||||
return;
|
||||
|
||||
dprintf ("Selected sources key (%s) changed, reloading\n", entry->key);
|
||||
|
||||
for (l = source_data->selected_sources; l; l = l->next)
|
||||
g_free (l->data);
|
||||
source_data->selected_sources = NULL;
|
||||
|
||||
for (l = gconf_value_get_list (entry->value); l; l = l->next)
|
||||
{
|
||||
const char *source = gconf_value_get_string (l->data);
|
||||
|
||||
source_data->selected_sources =
|
||||
g_slist_prepend (source_data->selected_sources,
|
||||
g_strdup (source));
|
||||
}
|
||||
source_data->selected_sources =
|
||||
g_slist_reverse (source_data->selected_sources);
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
}
|
||||
|
||||
static void
|
||||
calendar_sources_load_sources (CalendarSources *sources,
|
||||
CalendarSourceData *source_data,
|
||||
const char *sources_key,
|
||||
const char *selected_sources_key,
|
||||
const char *selected_sources_dir)
|
||||
{
|
||||
GConfClient *gconf_client;
|
||||
GError *error;
|
||||
|
||||
dprintf ("---------------------------\n");
|
||||
dprintf ("Loading sources:\n");
|
||||
dprintf (" sources_key: %s\n", sources_key);
|
||||
dprintf (" selected_sources_key: %s\n", selected_sources_key);
|
||||
dprintf (" selected_sources_dir: %s\n", selected_sources_dir);
|
||||
|
||||
gconf_client = sources->priv->gconf_client;
|
||||
|
||||
error = NULL;
|
||||
source_data->selected_sources = gconf_client_get_list (gconf_client,
|
||||
selected_sources_key,
|
||||
GCONF_VALUE_STRING,
|
||||
&error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("Failed to get selected sources from '%s': %s\n",
|
||||
selected_sources_key,
|
||||
error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
gconf_client_add_dir (gconf_client,
|
||||
selected_sources_dir,
|
||||
GCONF_CLIENT_PRELOAD_NONE,
|
||||
NULL);
|
||||
source_data->selected_sources_dir = g_strdup (selected_sources_dir);
|
||||
|
||||
source_data->selected_sources_listener =
|
||||
gconf_client_notify_add (gconf_client,
|
||||
selected_sources_dir,
|
||||
(GConfClientNotifyFunc) calendar_sources_selected_sources_notify,
|
||||
source_data, NULL, NULL);
|
||||
|
||||
source_data->esource_list = e_source_list_new_for_gconf (gconf_client, sources_key);
|
||||
g_signal_connect (source_data->esource_list, "changed",
|
||||
G_CALLBACK (calendar_sources_esource_list_changed),
|
||||
source_data);
|
||||
|
||||
calendar_sources_load_esource_list (source_data);
|
||||
|
||||
source_data->loaded = TRUE;
|
||||
|
||||
dprintf ("---------------------------\n");
|
||||
}
|
||||
|
||||
GSList *
|
||||
calendar_sources_get_appointment_sources (CalendarSources *sources)
|
||||
{
|
||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
||||
|
||||
if (!sources->priv->appointment_sources.loaded)
|
||||
{
|
||||
calendar_sources_load_sources (sources,
|
||||
&sources->priv->appointment_sources,
|
||||
CALENDAR_SOURCES_APPOINTMENT_SOURCES_KEY,
|
||||
CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_KEY,
|
||||
CALENDAR_SOURCES_SELECTED_APPOINTMENT_SOURCES_DIR);
|
||||
}
|
||||
|
||||
return sources->priv->appointment_sources.clients;
|
||||
}
|
||||
|
||||
GSList *
|
||||
calendar_sources_get_task_sources (CalendarSources *sources)
|
||||
{
|
||||
g_return_val_if_fail (CALENDAR_IS_SOURCES (sources), NULL);
|
||||
|
||||
if (!sources->priv->task_sources.loaded)
|
||||
{
|
||||
calendar_sources_load_sources (sources,
|
||||
&sources->priv->task_sources,
|
||||
CALENDAR_SOURCES_TASK_SOURCES_KEY,
|
||||
CALENDAR_SOURCES_SELECTED_TASK_SOURCES_KEY,
|
||||
CALENDAR_SOURCES_SELECTED_TASK_SOURCES_DIR);
|
||||
}
|
||||
|
||||
return sources->priv->task_sources.clients;
|
||||
}
|
66
src/calendar-client/calendar-sources.h
Normal file
66
src/calendar-client/calendar-sources.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* Mark McLoughlin <mark@skynet.ie>
|
||||
* William Jon McCann <mccann@jhu.edu>
|
||||
* Martin Grimme <martin@pycage.de>
|
||||
* Christian Kellner <gicmo@xatom.net>
|
||||
*/
|
||||
|
||||
#ifndef __CALENDAR_SOURCES_H__
|
||||
#define __CALENDAR_SOURCES_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CALENDAR_TYPE_SOURCES (calendar_sources_get_type ())
|
||||
#define CALENDAR_SOURCES(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CALENDAR_TYPE_SOURCES, CalendarSources))
|
||||
#define CALENDAR_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
|
||||
#define CALENDAR_IS_SOURCES(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CALENDAR_TYPE_SOURCES))
|
||||
#define CALENDAR_IS_SOURCES_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), CALENDAR_TYPE_SOURCES))
|
||||
#define CALENDAR_SOURCES_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), CALENDAR_TYPE_SOURCES, CalendarSourcesClass))
|
||||
|
||||
typedef struct _CalendarSources CalendarSources;
|
||||
typedef struct _CalendarSourcesClass CalendarSourcesClass;
|
||||
typedef struct _CalendarSourcesPrivate CalendarSourcesPrivate;
|
||||
|
||||
struct _CalendarSources
|
||||
{
|
||||
GObject parent;
|
||||
CalendarSourcesPrivate *priv;
|
||||
};
|
||||
|
||||
struct _CalendarSourcesClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* appointment_sources_changed) (CalendarSources *sources);
|
||||
void (* task_sources_changed) (CalendarSources *sources);
|
||||
};
|
||||
|
||||
|
||||
GType calendar_sources_get_type (void) G_GNUC_CONST;
|
||||
CalendarSources *calendar_sources_get (void);
|
||||
GSList *calendar_sources_get_appointment_sources (CalendarSources *sources);
|
||||
GSList *calendar_sources_get_task_sources (CalendarSources *sources);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CALENDAR_SOURCES_H__ */
|
255
src/shell-evolution-event-source.c
Normal file
255
src/shell-evolution-event-source.c
Normal file
@ -0,0 +1,255 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "calendar-client/calendar-client.h"
|
||||
#include "shell-evolution-event-source.h"
|
||||
|
||||
|
||||
struct _ShellEvolutionEventSourceClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
struct _ShellEvolutionEventSource {
|
||||
GObject parent;
|
||||
CalendarClient *client;
|
||||
/* The month that we are currently requesting events from */
|
||||
gint req_year;
|
||||
gint req_mon; /* starts at 1, not zero */
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
CHANGED_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (ShellEvolutionEventSource, shell_evolution_event_source, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
on_tasks_changed (CalendarClient *client,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (user_data);
|
||||
/* g_print ("on tasks changed\n"); */
|
||||
g_signal_emit (source, signals[CHANGED_SIGNAL], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_appointments_changed (CalendarClient *client,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (user_data);
|
||||
/* g_print ("on appointments changed\n"); */
|
||||
g_signal_emit (source, signals[CHANGED_SIGNAL], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_evolution_event_source_init (ShellEvolutionEventSource *source)
|
||||
{
|
||||
source->client = calendar_client_new ();
|
||||
g_signal_connect (source->client,
|
||||
"tasks-changed",
|
||||
G_CALLBACK (on_tasks_changed),
|
||||
source);
|
||||
g_signal_connect (source->client,
|
||||
"appointments-changed",
|
||||
G_CALLBACK (on_appointments_changed),
|
||||
source);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_evolution_event_source_finalize (GObject *object)
|
||||
{
|
||||
ShellEvolutionEventSource *source = SHELL_EVOLUTION_EVENT_SOURCE (object);
|
||||
g_object_unref (source->client);
|
||||
G_OBJECT_CLASS (shell_evolution_event_source_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_evolution_event_source_class_init (ShellEvolutionEventSourceClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = shell_evolution_event_source_finalize;
|
||||
|
||||
signals[CHANGED_SIGNAL] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
}
|
||||
|
||||
ShellEvolutionEventSource *
|
||||
shell_evolution_event_source_new (void)
|
||||
{
|
||||
return SHELL_EVOLUTION_EVENT_SOURCE (g_object_new (SHELL_TYPE_EVOLUTION_EVENT_SOURCE, NULL));
|
||||
}
|
||||
|
||||
void
|
||||
shell_evolution_event_source_request_range (ShellEvolutionEventSource *source,
|
||||
gint64 msec_begin,
|
||||
gint64 msec_end)
|
||||
{
|
||||
GDateTime *middle;
|
||||
|
||||
/* The CalendarClient type is a convenience wrapper on top of
|
||||
* Evolution Data Server. It is based on the assumption that only
|
||||
* a single month is shown at a time.
|
||||
*
|
||||
* To avoid reimplemting all the work already done in CalendarClient
|
||||
* we make the same assumption. This means that we only show events
|
||||
* in the month that is in the middle of @msec_begin and
|
||||
* @msec_end. Since the Shell displays a month at a time (plus the
|
||||
* days before and after) it works out just fine.
|
||||
*/
|
||||
|
||||
middle = g_date_time_new_from_unix_utc ((msec_begin + msec_end) / 2 / 1000);
|
||||
g_date_time_get_ymd (middle, &source->req_year, &source->req_mon, NULL);
|
||||
g_date_time_unref (middle);
|
||||
calendar_client_select_month (source->client, source->req_mon - 1, source->req_year);
|
||||
}
|
||||
|
||||
static gint
|
||||
event_cmp (gconstpointer a,
|
||||
gconstpointer b)
|
||||
{
|
||||
const ShellEvolutionEvent *ea;
|
||||
const ShellEvolutionEvent *eb;
|
||||
|
||||
ea = a;
|
||||
eb = b;
|
||||
if (ea->msec_begin < eb->msec_begin)
|
||||
return -1;
|
||||
else if (ea->msec_begin > eb->msec_begin)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_evolution_event_source_get_events:
|
||||
* @source: A #ShellEvolutionEventSource.
|
||||
* @msec_begin: Start date (milli-seconds since Epoch).
|
||||
* @msec_end: End date (milli-seconds since Epoch).
|
||||
*
|
||||
* Gets all events that occur between @msec_begin and @msec_end.
|
||||
*
|
||||
* Returns: (element-type ShellEvolutionEvent) (transfer full): List of events.
|
||||
*/
|
||||
GList *
|
||||
shell_evolution_event_source_get_events (ShellEvolutionEventSource *source,
|
||||
gint64 msec_begin,
|
||||
gint64 msec_end)
|
||||
{
|
||||
GList *result;
|
||||
GDateTime *cur_date;
|
||||
GDateTime *begin_date;
|
||||
GDateTime *end_date;
|
||||
|
||||
g_return_val_if_fail (msec_begin <= msec_end, NULL);
|
||||
|
||||
result = NULL;
|
||||
|
||||
begin_date = g_date_time_new_from_unix_utc (msec_begin / 1000);
|
||||
end_date = g_date_time_new_from_unix_utc (msec_end / 1000);
|
||||
cur_date = g_date_time_ref (begin_date);
|
||||
do
|
||||
{
|
||||
gint year, mon, day;
|
||||
GDateTime *next_date;
|
||||
|
||||
g_date_time_get_ymd (cur_date, &year, &mon, &day);
|
||||
/* g_print ("y=%04d m=%02d d=%02d\n", year, mon, day); */
|
||||
|
||||
/* Silently drop events not in range (see comment in
|
||||
* shell_evolution_event_source_request_range() above)
|
||||
*/
|
||||
if (!(year == source->req_year && mon == source->req_mon))
|
||||
{
|
||||
/* g_print ("skipping day\n"); */
|
||||
}
|
||||
else
|
||||
{
|
||||
GSList *events;
|
||||
GSList *l;
|
||||
calendar_client_select_day (source->client, day);
|
||||
events = calendar_client_get_events (source->client, CALENDAR_EVENT_APPOINTMENT);
|
||||
/* g_print ("num_events: %d\n", g_slist_length (events)); */
|
||||
for (l = events; l; l = l->next)
|
||||
{
|
||||
CalendarAppointment *appointment = l->data;
|
||||
ShellEvolutionEvent *event;
|
||||
gint64 start_time;
|
||||
|
||||
if (appointment->is_all_day)
|
||||
{
|
||||
start_time = g_date_time_to_unix (cur_date) * G_GINT64_CONSTANT (1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
start_time = appointment->start_time * G_GINT64_CONSTANT (1000);
|
||||
}
|
||||
event = shell_evolution_event_new (appointment->summary,
|
||||
appointment->is_all_day,
|
||||
start_time);
|
||||
result = g_list_prepend (result, event);
|
||||
}
|
||||
g_slist_foreach (events, (GFunc) calendar_event_free, NULL);
|
||||
g_slist_free (events);
|
||||
}
|
||||
|
||||
next_date = g_date_time_add_days (cur_date, 1);
|
||||
g_date_time_unref (cur_date);
|
||||
cur_date = next_date;
|
||||
}
|
||||
while (g_date_time_difference (end_date, cur_date) > 0);
|
||||
g_date_time_unref (begin_date);
|
||||
g_date_time_unref (end_date);
|
||||
|
||||
result = g_list_sort (result, event_cmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
G_DEFINE_BOXED_TYPE (ShellEvolutionEvent,
|
||||
shell_evolution_event,
|
||||
shell_evolution_event_copy,
|
||||
shell_evolution_event_free);
|
||||
|
||||
void
|
||||
shell_evolution_event_free (ShellEvolutionEvent *event)
|
||||
{
|
||||
g_free (event->summary);
|
||||
g_free (event);
|
||||
}
|
||||
|
||||
ShellEvolutionEvent *
|
||||
shell_evolution_event_copy (ShellEvolutionEvent *event)
|
||||
{
|
||||
ShellEvolutionEvent *copy;
|
||||
copy = g_memdup (event, sizeof (ShellEvolutionEvent));
|
||||
copy->summary = g_strdup (event->summary);
|
||||
return copy;
|
||||
}
|
||||
|
||||
ShellEvolutionEvent *
|
||||
shell_evolution_event_new (const gchar *summary,
|
||||
gboolean all_day,
|
||||
gint64 msec_begin)
|
||||
{
|
||||
ShellEvolutionEvent *event;
|
||||
event = g_new0 (ShellEvolutionEvent, 1);
|
||||
event->summary = g_strdup (summary);
|
||||
event->all_day = all_day;
|
||||
event->msec_begin = msec_begin;
|
||||
return event;
|
||||
}
|
45
src/shell-evolution-event-source.h
Normal file
45
src/shell-evolution-event-source.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __SHELL_EVOLUTION_EVENT_SOURCE_H__
|
||||
#define __SHELL_EVOLUTION_EVENT_SOURCE_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ShellEvolutionEvent ShellEvolutionEvent;
|
||||
|
||||
struct _ShellEvolutionEvent
|
||||
{
|
||||
gchar *summary;
|
||||
gboolean all_day;
|
||||
gint64 msec_begin;
|
||||
};
|
||||
|
||||
GType shell_evolution_event_get_type (void) G_GNUC_CONST;
|
||||
ShellEvolutionEvent *shell_evolution_event_new (const gchar *summary,
|
||||
gboolean all_day,
|
||||
gint64 msec_begin);
|
||||
ShellEvolutionEvent *shell_evolution_event_copy (ShellEvolutionEvent *event);
|
||||
void shell_evolution_event_free (ShellEvolutionEvent *event);
|
||||
|
||||
typedef struct _ShellEvolutionEventSource ShellEvolutionEventSource;
|
||||
typedef struct _ShellEvolutionEventSourceClass ShellEvolutionEventSourceClass;
|
||||
|
||||
#define SHELL_TYPE_EVOLUTION_EVENT_SOURCE (shell_evolution_event_source_get_type ())
|
||||
#define SHELL_EVOLUTION_EVENT_SOURCE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSource))
|
||||
#define SHELL_EVOLUTION_EVENT_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSourceClass))
|
||||
#define SHELL_IS_EVOLUTION_EVENT_SOURCE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_EVOLUTION_EVENT_SOURCE))
|
||||
#define SHELL_IS_EVOLUTION_EVENT_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_EVOLUTION_EVENT_SOURCE))
|
||||
#define SHELL_EVOLUTION_EVENT_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_EVOLUTION_EVENT_SOURCE, ShellEvolutionEventSourceClass))
|
||||
|
||||
GType shell_evolution_event_source_get_type (void) G_GNUC_CONST;
|
||||
ShellEvolutionEventSource *shell_evolution_event_source_new (void);
|
||||
void shell_evolution_event_source_request_range (ShellEvolutionEventSource *source,
|
||||
gint64 msec_begin,
|
||||
gint64 msec_end);
|
||||
GList *shell_evolution_event_source_get_events (ShellEvolutionEventSource *source,
|
||||
gint64 msec_begin,
|
||||
gint64 msec_end);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_EVOLUTION_EVENT_SOURCE_H__ */
|
@ -62,7 +62,8 @@ fi
|
||||
# libxklavier, libxml2, ORBit2, pam, python, readline,
|
||||
# spidermonkey ({mozilla,firefox,xulrunner}-js), startup-notification,
|
||||
# xdamage, icon-naming-utils, upower, libtool-ltdl, libvorbis,
|
||||
# libgcrypt, libtasn1, libgnome-keyring, libgtop, cups
|
||||
# libgcrypt, libtasn1, libgnome-keyring, libgtop, cups,
|
||||
# evolution-data-server
|
||||
#
|
||||
# Non-devel packages needed by gnome-shell and its deps:
|
||||
# glxinfo, gstreamer-plugins-base, gstreamer-plugins-good,
|
||||
@ -83,7 +84,7 @@ if test "x$system" = xUbuntu -o "x$system" = xDebian -o "x$system" = xLinuxMint
|
||||
xulrunner-dev xserver-xephyr gnome-terminal libcroco3-dev
|
||||
libgstreamer0.10-dev gstreamer0.10-plugins-base gstreamer0.10-plugins-good
|
||||
libltdl-dev libvorbis-dev libxklavier-dev libgnome-keyring-dev
|
||||
libupower-glib-dev libcups2-dev
|
||||
libupower-glib-dev libcups2-dev evolution-data-server-dev
|
||||
"
|
||||
|
||||
if apt-cache show autopoint > /dev/null 2> /dev/null; then
|
||||
@ -121,7 +122,7 @@ if test "x$system" = xFedora ; then
|
||||
startup-notification-devel xorg-x11-server-Xephyr gnome-terminal zenity
|
||||
icon-naming-utils upower-devel libtool-ltdl-devel libvorbis-devel
|
||||
libxklavier-devel libgcrypt-devel libtasn1-devel libtasn1-tools
|
||||
libgnome-keyring-devel libgtop2-devel cups-devel
|
||||
libgnome-keyring-devel libgtop2-devel cups-devel evolution-data-server-devel
|
||||
"
|
||||
|
||||
if expr $version \>= 14 > /dev/null ; then
|
||||
@ -147,7 +148,7 @@ if test "x$system" = xSUSE -o "x$system" = "xSUSE LINUX" ; then
|
||||
libgtop-devel libpulse-devel libtiff-devel cups-devel libffi-devel \
|
||||
orbit2-devel libwnck-devel xorg-x11-proto-devel readline-devel \
|
||||
mozilla-xulrunner191-devel libcroco-devel \
|
||||
xorg-x11-devel xorg-x11 xorg-x11-server-extra \
|
||||
xorg-x11-devel xorg-x11 xorg-x11-server-extra evolution-data-server-devel \
|
||||
; do
|
||||
if ! rpm -q $pkg > /dev/null 2>&1; then
|
||||
reqd="$pkg $reqd"
|
||||
@ -168,7 +169,7 @@ if test "x$system" = xMandrivaLinux ; then
|
||||
intltool ffi5-devel libwnck-1-devel GL-devel ORBit2-devel \
|
||||
readline-devel libxulrunner-devel \
|
||||
libxdamage-devel mesa-demos x11-server-xephyr zenity \
|
||||
libcroco0.6-devel \
|
||||
libcroco0.6-devel libevolution-data-server3-devel \
|
||||
; do
|
||||
if ! rpm -q --whatprovides $pkg > /dev/null 2>&1; then
|
||||
reqd="$pkg $reqd"
|
||||
|
Loading…
Reference in New Issue
Block a user