Some changes to be more compatible with Python 3 in the future
[joel/kofoto.git] / src / packages / kofoto / gkofoto / imageversionsdialog.py
1 import gtk
2 from kofoto.gkofoto.environment import env
3 from kofoto.structclass import makeStructClass
4 from kofoto.shelf import CategoryPresentError, ImageVersionType
5
6 RowDataStruct = makeStructClass(
7     "imageVersion",
8     "commentTextBuffer",
9     "primaryButton",
10     "importantButton",
11     "originalButton",
12     "otherButton")
13
14 class ImageVersionsDialog:
15     tableWidth = 3
16
17     def __init__(self, model):
18         self._mergeImages = []
19         self._isMerge = False
20         self._model = model
21         self._versionDataList = []
22         self._widgets = gtk.glade.XML(
23             env.gladeFile, "imageVersionsDialog")
24         self._dialog = self._widgets.get_widget("imageVersionsDialog")
25         self._cancelButton = self._widgets.get_widget("cancelButton")
26         self._okButton = self._widgets.get_widget("okButton")
27
28         self._cancelButton.connect("clicked", self._onCancel)
29         self._okButton.connect("clicked", self._onOk)
30
31         scrolledWindow = self._widgets.get_widget("scrolledWindow")
32         self._table = gtk.Table(1, ImageVersionsDialog.tableWidth)
33         self._table.set_border_width(5)
34         self._table.set_row_spacings(5)
35         self._table.set_col_spacings(10)
36         scrolledWindow.add_with_viewport(self._table)
37         self.__primaryRadioButtonGroup = None
38
39     def runViewImageVersions(self, image):
40         self._isMerge = False
41         self._run([image])
42
43     def runMergeImages(self, images):
44         assert len(images) > 1
45         self._isMerge = True
46         self._mergeImages = images
47         self._run(images)
48
49     def _run(self, images):
50         for image in images:
51             for imageVersion in image.getImageVersions():
52                 self._addRow(imageVersion)
53         self._table.show_all()
54         x, y = self._dialog.get_position()
55         _, height = self._dialog.get_size()
56         hackyConstant = 89 # TODO: How to calculate this properly?
57         newheight = min(800, self._table.size_request()[1] + hackyConstant)
58         self._dialog.move(x, max(0, y - ((newheight - height) / 2)))
59         self._dialog.resize(450, newheight)
60         self._dialog.run()
61
62     def _onCancel(self, *unused):
63         self._dialog.destroy()
64
65     def _onOk(self, *unused):
66         for data in self._versionDataList:
67             tb = data.commentTextBuffer
68             comment = tb.get_text(
69                 tb.get_start_iter(), tb.get_end_iter()).decode("utf-8")
70             data.imageVersion.setComment(comment)
71             if data.primaryButton.get_active():
72                 data.imageVersion.makePrimary()
73             if data.importantButton.get_active():
74                 data.imageVersion.setType(ImageVersionType.Important)
75             elif data.originalButton.get_active():
76                 data.imageVersion.setType(ImageVersionType.Original)
77             elif data.otherButton.get_active():
78                 data.imageVersion.setType(ImageVersionType.Other)
79             else:
80                 assert False
81
82         if self._isMerge:
83             #
84             # The mother image below is the image of the primary
85             # version, i.e. the image that will adopt all image
86             # versions.
87             #
88
89             motherImage = None
90             for data in self._versionDataList:
91                 if data.primaryButton.get_active():
92                     motherImage = data.imageVersion.getImage()
93                     break
94             assert motherImage
95
96             for image in self._mergeImages:
97                 if image != motherImage:
98                     for key, value in image.getAttributeMap().iteritems():
99                         motherImage.setAttribute(key, value, overwrite=False)
100
101             for data in self._versionDataList:
102                 data.imageVersion.setImage(motherImage)
103
104             descriptionTexts = []
105             for image in self._mergeImages:
106                 description = image.getAttribute(u"description")
107                 if description:
108                     descriptionTexts.append(description)
109                 if image == motherImage:
110                     continue
111                 for category in image.getCategories():
112                     try:
113                         motherImage.addCategory(category)
114                     except CategoryPresentError:
115                         pass
116                 for album in image.getParents():
117                     children = list(album.getChildren())
118                     if motherImage in children:
119                         # Both motherImage and image are present in
120                         # children, so just remove image to avoid
121                         # duplicates in album.
122                         pass
123                     else:
124                         # Replace image with motherImage.
125                         for i, child in enumerate(children):
126                             if child == image:
127                                 children[i] = motherImage
128                         album.setChildren(children)
129                 env.shelf.deleteImage(image.getId())
130             description = "\n\n".join(descriptionTexts)
131             if len(descriptionTexts) > 1:
132                 widgets = gtk.glade.XML(
133                     env.gladeFile, "editMergedDescriptionDialog")
134                 dialog = widgets.get_widget("editMergedDescriptionDialog")
135                 textBuffer = widgets.get_widget("descriptionText").get_buffer()
136                 textBuffer.set_text(description)
137                 dialog.run()
138                 dialog.destroy()
139                 motherImage.setAttribute(
140                     u"description",
141                     textBuffer.get_text(
142                         textBuffer.get_start_iter(),
143                         textBuffer.get_end_iter()).decode("utf-8"))
144             env.mainwindow.reloadObjectList()
145         else:
146             self._model.reloadSelectedRows()
147         self._dialog.destroy()
148
149     def _addRow(self, imageVersion):
150         table = self._table
151         data = RowDataStruct()
152         self._versionDataList.append(data)
153         data.imageVersion = imageVersion
154         number = len(self._versionDataList) - 1
155         table.resize(number + 1, ImageVersionsDialog.tableWidth)
156
157         #
158         # Column one.
159         #
160         image = gtk.Image()
161         try:
162             thumbnailLocation, _, _ = env.imageCache.get(
163                 imageVersion.getLocation(), 128, 128)
164             image.set_from_file(thumbnailLocation)
165         except OSError:
166             image.set_from_pixbuf(env.unknownImageIconPixbuf)
167         table.attach(
168             image, 0, 1, number, number + 1, gtk.SHRINK, gtk.SHRINK)
169
170         #
171         # Column two.
172         #
173         buttonBox = gtk.VBox()
174         table.attach(
175             buttonBox, 1, 2, number, number + 1, gtk.SHRINK, gtk.FILL)
176         primaryButton = gtk.RadioButton(self.__primaryRadioButtonGroup, "Primary")
177         buttonBox.pack_start(primaryButton, False, False)
178         data.primaryButton = primaryButton
179         if not self.__primaryRadioButtonGroup:
180             self.__primaryRadioButtonGroup = primaryButton
181         primaryButton.set_active(imageVersion.isPrimary())
182
183         typeFrame = gtk.Frame("Type")
184         buttonBox.pack_start(typeFrame, False, False)
185
186         typeButtonBox = gtk.VBox()
187         typeFrame.add(typeButtonBox)
188
189         importantButton = gtk.RadioButton(None, "Important")
190         typeButtonBox.add(importantButton)
191         data.importantButton = importantButton
192         importantButton.set_active(
193             imageVersion.getType() == ImageVersionType.Important)
194
195         originalButton = gtk.RadioButton(importantButton, "Original")
196         typeButtonBox.add(originalButton)
197         data.originalButton = originalButton
198         originalButton.set_active(
199             imageVersion.getType() == ImageVersionType.Original)
200
201         otherButton = gtk.RadioButton(importantButton, "Other")
202         typeButtonBox.add(otherButton)
203         data.otherButton = otherButton
204         otherButton.set_active(
205             imageVersion.getType() == ImageVersionType.Other)
206
207         #
208         # Column three.
209         #
210         scrolledWindow = gtk.ScrolledWindow()
211         scrolledWindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
212         scrolledWindow.set_shadow_type(gtk.SHADOW_IN)
213         textView = gtk.TextView()
214         scrolledWindow.add(textView)
215         data.commentTextBuffer = textView.get_buffer()
216         textView.set_wrap_mode(gtk.WRAP_WORD)
217         textView.get_buffer().set_text(imageVersion.getComment())
218         table.attach(
219             scrolledWindow, 2, 3, number, number + 1,
220             gtk.FILL|gtk.EXPAND, gtk.FILL)